Si vous utilisez Bash, vous n'avez même pas besoin d'utiliser grep
:
files="*.jpg"
regex="[0-9]+_([a-z]+)_[0-9a-z]*"
for f in $files # unquoted in order to allow the glob to expand
do
if [[ $f =~ $regex ]]
then
name="${BASH_REMATCH[1]}"
echo "${name}.jpg" # concatenate strings
name="${name}.jpg" # same thing stored in a variable
else
echo "$f doesn't match" >&2 # this could get noisy if there are a lot of non-matching files
fi
done
Il est préférable de mettre la regex dans une variable. Certains motifs ne fonctionneront pas s'ils sont inclus littéralement.
Cela utilise =~
qui est l'opérateur de correspondance regex de Bash. Les résultats de la correspondance sont enregistrés dans un tableau appelé $BASH_REMATCH
. Le premier groupe de capture est stocké dans l'index 1, le second (le cas échéant) dans l'index 2, etc. L'index zéro est la correspondance complète.
Il faut savoir que sans ancres, cette regex (et celle qui utilise la fonction grep
) correspondra à tous les exemples suivants et à d'autres, ce qui n'est peut-être pas ce que vous recherchez :
123_abc_d4e5
xyz123_abc_d4e5
123_abc_d4e5.xyz
xyz123_abc_d4e5.xyz
Pour éliminer les deuxième et quatrième exemples, faites votre regex comme ceci :
^[0-9]+_([a-z]+)_[0-9a-z]*
qui dit que la chaîne doit commencer avec un ou plusieurs chiffres. Le carat représente le début de la chaîne. Si vous ajoutez un signe dollar à la fin de la regex, comme ceci :
^[0-9]+_([a-z]+)_[0-9a-z]*$
alors le troisième exemple sera également éliminé puisque le point ne fait pas partie des caractères de la regex et que le signe dollar représente la fin de la chaîne. Notez que le quatrième exemple échoue également à cette correspondance.
Si vous avez GNU grep
(vers 2.5 ou plus tard, je pense, lorsque la \K
a été ajouté) :
name=$(echo "$f" | grep -Po '(?i)[0-9]+_\K[a-z]+(?=_[0-9a-z]*)').jpg
El \K
(look-behind de longueur variable) fait correspondre le motif précédent, mais n'inclut pas la correspondance dans le résultat. L'équivalent en longueur fixe est (?<=)
- le motif serait inclus avant la parenthèse fermante. Vous devez utiliser \K
si les quantificateurs peuvent correspondre à des chaînes de caractères de différentes longueurs (par ex. +
, *
, {2,4}
).
El (?=)
correspond à des motifs de longueur fixe ou variable et est appelé "look-ahead". Il n'inclut pas non plus la chaîne trouvée dans le résultat.
Afin de rendre la correspondance insensible à la casse, l'option (?i)
est utilisé. Il affecte les motifs qui le suivent, sa position est donc importante.
La regex peut devoir être ajustée en fonction de la présence d'autres caractères dans le nom du fichier. Vous remarquerez que dans ce cas, je montre un exemple de concaténation d'une chaîne en même temps que la sous-chaîne est capturée.
31 votes
Est-ce que grep vraiment unix plus pur que sed ?
7 votes
Ah, je ne voulais pas suggérer ça. J'espérais simplement qu'une solution pourrait être trouvée en utilisant un outil que j'essaie spécifiquement d'apprendre ici. S'il n'est pas possible de résoudre le problème en utilisant
grep
entoncessed
serait génial, s'il est possible de le résoudre en utilisantsed
.6 votes
J'aurais dû mettre un :) sur cette phrase...
0 votes
Psh, mon cerveau est bien trop grillé aujourd'hui haha.
3 votes
@martinclayton Ce serait un argument intéressant. Je pense vraiment que sed, (ou ed pour être précis) serait unix plus ancien (et donc plus pur ? peut-être ?) car grep tire son nom de l'expression ed g(lobal)/re(gular expression)/p(rint).