Que fait% dans les chaînes de shell Linux?

28

Dans le shell Linux, que fait%, comme dans:

for file in *.png.jpg; do
  mv "$file" "${file%.png.jpg}.jpg"
done
Nissim Nanach
la source
4
Chaque fois que je recherche cela, je trouve généralement la bonne section de la page de manuel bash en recherchant %%ou ##, car c'est assez mémorable et rare pour trouver rapidement la bonne section. man bash /##
Peter Cordes
3
@PeterCordes Je me souviens toujours de ceci par "C'est 5%, donc% est à la fin et donc coupe de la fin. Et c'est # 5, donc # est au début et coupe depuis le début." Mais parfois je mélange même celui-ci…
glglgl
2
@glglgl: sur un clavier américain typique, se #trouve immédiatement à gauche $et %immédiatement à droite. Aucun mnémonique nécessaire --- regardez simplement vers le bas. (C'est probablement au moins en partie pourquoi ces symboles ont été choisis.)
Kevin J. Chase
@ KevinJ.Chase Tout le monde dans le monde n'a pas de clavier américain typique. Mais en effet, sur un clavier allemand,% a également raison de $, ce qui pourrait être un début pour la mémorisation.
glglgl

Réponses:

29

Quand %est utilisé dans le modèle, ${variable%substring}il renverra le contenu de variablel'occurrence la plus courte de substringsupprimé de l'arrière de variable.

Cette fonction prend en charge les modèles génériques - c'est pourquoi elle accepte l'étoile (astérisque) comme sous-site pour zéro ou plusieurs caractères.

Il convient de mentionner que cela est spécifique à Bash - les autres interpréteurs Linux ne contiennent pas nécessairement cette fonction.

Si vous souhaitez en savoir plus sur la manipulation de chaînes dans Bash, je vous suggère fortement de lire cette page. Entre autres fonctions pratiques, il - par exemple - explique ce que cela %%fait :)

Edit: j'ai oublié de mentionner que lorsqu'il est utilisé dans le modèle $((variable%number))ou $((variable1%$variable2))le %caractère fonctionnera comme opérateur modulo. DavidPostill a des liens de documentation plus spécifiques dans sa réponse.

Lorsqu'il %est utilisé dans un contexte différent, il ne doit être reconnu que comme un caractère régulier.

Marek Rost
la source
2
L'opérateur prend en charge les modèles génériques , pas les expressions régulières.
gardenhead
Comme gardenhead l'a mentionné - il prend en charge les modèles globaux, pas les expressions régulières. En expression régulière, une étoile signifie zéro ou plus du caractère précédent.
slebetman
5
Le guide auquel vous avez lié n'est pas du tout recommandé par la plupart des utilisateurs d'échange de pile Unix et Linux . Je recommande plutôt le guide Wooledge Bash .
Wildcard
3
Les opérateurs de suppression de préfixe et de suffixe sont standard , ils doivent donc être utilisables dans n'importe quel shshell compatible, pas seulement Bash. (mais peut-être pas dedans cshet autres).
ilkkachu
1
Un autre contexte dans lequel %est utilisé est dans les spécificateurs de format pour printf.
pause jusqu'à nouvel ordre.
9

Manuel de référence Bash: Expansion des paramètres du shell

${parameter%word}
${parameter%%word}

Le mot est développé pour produire un modèle comme dans l'expansion du nom de fichier. Si le modèle correspond à une portion de fin de la valeur développée du paramètre , le résultat de l'expansion est la valeur du paramètre avec le modèle de correspondance le plus court (le ‘%’cas) ou le modèle de correspondance le plus long (le ‘%%’cas) supprimé. Si le paramètre est ‘@’ou ‘*’,l'opération de suppression de motif est appliquée à chaque paramètre de position tour à tour, et l'expansion est la liste résultante. Si le paramètre est une variable de tableau indexée avec ‘@’ ou‘*’, l'opération de suppression de modèle est appliquée à chaque membre de la matrice à son tour, et l'expansion est la liste résultante.

Steven
la source
2
NB: certaines extensions de paramètres, y compris%, sont des fonctionnalités posix prises en charge par de nombreux shells.
kojiro
7

En expérimentant, je trouve qu'une correspondance après% est supprimée, lorsque la chaîne est placée entre accolades (accolades).

Pour illustrer:

touch abcd         # Create file abcd

for file in ab*; do
 echo $file        # echoes the filename
 echo $file%       # echoes the filename plus "%"
 echo ${file%}     # echoes the filename
 echo "${file%}"   # echoes the filename
 echo
 echo "${file%c*}" # Discard anything after % matching c*
 echo "${file%*}"  # * is not greedy
 echo ${file%c*}   # Without quotes works too
 echo "${file%c}"  # No match after %, no effect
 echo $file%c*     # Without {} fails
done

Voici la sortie:

abcd
abcd%
abcd
abcd

ab
abcd
ab
abcd
abcd%c*
Nissim Nanach
la source
7

Dans Linux shell ( bash), que fait %-on?

for file in *.png.jpg; do
  mv "$file" "${file%.png.jpg}.jpg"
done

Dans ce cas particulier, l' opérateur %is pattern matching (notez qu'il peut également s'agir d'un opérateur modulo ).


Opérateur de correspondance de motifs

$ {var% $ Pattern}, $ {var %% $ Pattern}

${var%$Pattern}Supprimer de $varla partie la plus courte $Patternqui correspond à l'extrémité arrière de $var.

${var%%$Pattern}Retirez de $varla partie la plus longue $Patternqui correspond à l'arrière de $var.

Exemple: correspondance de motifs dans la substitution de paramètres

#!/bin/bash
# patt-matching.sh

# Pattern matching  using the # ## % %% parameter substitution operators.

var1=abcd12345abc6789
pattern1=a*c  # * (wild card) matches everything between a - c.

echo
echo "var1 = $var1"           # abcd12345abc6789
echo "var1 = ${var1}"         # abcd12345abc6789
                              # (alternate form)
echo "Number of characters in ${var1} = ${#var1}"
echo

echo "pattern1 = $pattern1"   # a*c  (everything between 'a' and 'c')
echo "--------------"
echo '${var1#$pattern1}  =' "${var1#$pattern1}"    #         d12345abc6789
# Shortest possible match, strips out first 3 characters  abcd12345abc6789
#                                     ^^^^^               |-|
echo '${var1##$pattern1} =' "${var1##$pattern1}"   #                  6789      
# Longest possible match, strips out first 12 characters  abcd12345abc6789
#                                    ^^^^^                |----------|

echo; echo; echo

pattern2=b*9            # everything between 'b' and '9'
echo "var1 = $var1"     # Still  abcd12345abc6789
echo
echo "pattern2 = $pattern2"
echo "--------------"
echo '${var1%pattern2}  =' "${var1%$pattern2}"     #     abcd12345a
# Shortest possible match, strips out last 6 characters  abcd12345abc6789
#                                     ^^^^                         |----|
echo '${var1%%pattern2} =' "${var1%%$pattern2}"    #     a
# Longest possible match, strips out last 12 characters  abcd12345abc6789
#                                    ^^^^                 |-------------|

# Remember, # and ## work from the left end (beginning) of string,
#           % and %% work from the right end.

echo

exit 0

Substitution des paramètres source


Opérateur Modulo

%

modulo ou mod (retourne le reste d'une opération de division entière)

bash$ expr 5 % 3
2

5/3 = 1, le reste 2

Opérateurs source

DavidPostill
la source
Peut-être que je l'ai: c'est pour des choses comme .*et le %définit comme non gourmand alors %%qu'il le rend gourmand? Donc, en fait, dans l'exemple de changement de nom, peu importe s'il faut utiliser %ou %%mais si c'était le cas mv "$file" "${file%.*png.jpg}.jpg"(notez le *), l'utilisation de %% renommerait tous les fichiers en juste .jpg, non?
Thomas Weller
@ThomasWeller Je pense que c'est correct. Mais je ne suis pas un expert bash.
DavidPostill
Dire "Supprimer ... la partie la plus courte de $Pattern" est faux car la variable $Patternn'est pas définie dans l'exemple, seul le texte "Motif" est supprimé $varlors de l'exécution de ${var%Pattern}ou ${var%%Pattern}. Peut-être que ce n'est qu'une faute de frappe, mais c'est encore un autre exemple de tldp.org qui a tort. BashGuide ou Bash Hackers Wiki sont tous les deux de bien meilleures références à mon humble avis.
John B
@JohnB Merci. Les deux liens ont marqué un signet. J'ai corrigé le texte dans la réponse.
DavidPostill