expansion du shell (A | B) dans les noms de fichiers?

9

Est-il possible d'élargir un orchoix dans le shell lors de la lecture d'un fichier par exemple.

Ce que je veux dire par là, c'est que, par exemple, grepprend en charge la syntaxe comme (A|B)pour faire correspondre A ou B dans un fichier.

De même, si j'ai ces fichiers:

file1.txt
file2.txt
file3.txt
file4.txt
file5.txt

Je pourrais le faire cat file{1..5}.txten bashélargissant la gamme. Existe-t-il un moyen équivalent de le faire pour quelques fichiers seulement?

Par exemple, cat file(1|5).txtet n'imprimez que ces 2?

Joe Healey
la source

Réponses:

16

Le modèle de globalisation de nom de fichier standard pour correspondre à un chiffre est [0-9]. Cela correspond à un seul chiffre:

cat file[0-9].txt

Pour n'en sélectionner que deux:

cat file[25].txt

Pour des nombres supérieurs à 9, l'expansion de l'accolade sera utile (mais voir la note ci-dessous pour la différence entre les modèles de globulation et les extensions de l'accolade):

cat file{25..60}.txt

Encore une fois, l'expansion des accolades permet également les numéros individuels:

cat file{12,45,900,xyz}.txt

(notez que dans l'exemple ci-dessus, l'expansion d'accolade n'implique pas de boucle arithmétique, mais génère simplement des noms en fonction des chaînes fournies).

Dans bash, avec l' extgloboption shell activée ( shopt -s extglob), les éléments suivants fonctionneront également:

cat file@(12|45|490|foo).txt

Le @(...)modèle correspondra à n'importe |lequel des modèles délimités inclus .


La différence entre les modèles globbing as [...]et @(...)et les extensions d'accolade est qu'une expansion d'accolade est générée sur la ligne de commande et peut ne pas correspondre à des noms existants dans le répertoire en cours. Un modèle de globbing de nom de fichier correspondra aux noms, mais le shell ne se plaindra pas si tous les noms possibles n'existent pas. Si aucun nom correspondant n'existe, le modèle restera non développé, sauf si l' nullgloboption shell est également définie, auquel cas le modèle est supprimé.

Exemple:

touch file1

ls file[0-9]

Ici, seule la liste des fichiers pour file1sera affichée.

Avec ls file{0..9}, lsse plaindrait de ne pas trouver file0, file2etc.

Dans l'exemple suivant, la première commande ne touchera que les noms existants qui correspondent au modèle donné, tandis que la deuxième ligne créera des fichiers qui n'existent pas déjà:

touch file[0-9]

touch file{0..9}
Kusalananda
la source
@thecarpy Je suis désolé, mais ce n'est pas un modèle qui correspondrait par exemple file45.txt. L'expression entre crochets [...]fonctionne exactement comme dans l'expression régulière mais utilise !à la place de ^pour dire "pas dans". Un [...]motif correspondra toujours à un seul caractère.
Kusalananda
Tu as raison! BTW, mon {1,2}n'est pas non plus conforme à POSIX ... a appris quelques nouvelles choses aujourd'hui!
thecarpy
2
Le fait que les extensions d'accolade ne correspondent pas nécessairement à de vrais fichiers peut être extrêmement utile, si vous l'utilisez pour (par exemple) générer des modèles vers lesquels passer grep, générer des URL vers lesquelles passer curl, etc., mais cela peut aussi être source de confusion. aux personnes habituées à travailler avec des globes.
Kevin
@Kevin Correct. Une extension d'accolade ne doit pas nécessairement concerner les noms de fichiers.
Kusalananda
7

La syntaxe à utiliser est celle file{1,2}qui évaluera vers file1et file2.

$ ls
$ touch file{1,2,3,4,5,6,7,8,9}
$ ls
file1  file2  file3  file4  file5  file6  file7  file8  file9

Comme Inian l'a également souligné ci-dessous ... il serait plus facile de le faire touch file{1..9}dans cet exemple ...

$ ls
$ touch file{1..9}
$ ls
file1  file2  file3  file4  file5  file6  file7  file8  file9

Vous pouvez également utiliser plusieurs expressions, comme:

$ ls
$ touch file{1..9}{a..z}
$ ls
file1a file1b file1c
[...]
file9x file9y file9z

Oui, ce qui précède créera 234 ( 9fois 26) fichiers.

la carpe
la source
1
Cette file{1,2} syntaxe est également pratique pour renommer des fichiers:mv some_very_long_filename.txt{,.bak}
Eric Duminil
6

Oui, vous pouvez utiliser l'expansion d'accolade dans le bashshell. Pour juste quelques fichiers, faites file{1..2}oufile{1,2}

Ou si vous craignez que les fichiers ne soient pas là dans certains cas, faites simplement une boucle,

for file in file{1..4}.txt; do
    [ -f "$file" ] || continue
    echo "$file" # Do other actions on file here
done

Ou si la simple concaténation est votre seule opération sur les fichiers et si vous ne savez pas quels fichiers ne pourraient pas être présents à un moment donné, il suffit de catles supprimer et de supprimer les erreurs. La redirection de l'erreur standard vers /dev/nullsupprimerait les erreurs si le fichier n'était pas disponible.

cat file{1,5}.txt 2>/dev/null

ou utilisez l'expression glob file[15]qui ne se plaint pas des erreurs si le fichier n'a pas été trouvé.

cat file[15].txt
Inian
la source
2
Non, pas de soucis concernant l'absence de fichiers, je voulais juste montrer le contenu de 2 fichiers numérotés, mais qui ne sont pas consécutifs, donc la file{1,5}syntaxe virgule était tout ce qui me manquait!
Joe Healey