Quelle est la différence entre `a [bc] d` (crochets) et` a {b, c} d` (accolades)?

28

Quelle est la difference entre a[bc]det a{b,c}d? Pourquoi les gens utilisent a{b,c}d-ils quand il y en a déjà a[bc]d?

Weijun Zhou
la source
Qui vous a dit d'utiliser command a[bc]d?
Jesse_b
3
Il a certainement ses utilités si on le comprend correctement.
Weijun Zhou
7
Je suppose que je ne comprends tout simplement pas comment la confusion entre les deux s'est produite.
Jesse_b
J'ai été explicitement interrogé par un collègue moins familier avec Linux à ce sujet, mais pas récemment.
Weijun Zhou
@Jesse_b Si vous ne les essayez qu'avec des opérations sur des fichiers comme lset que vous n'essayez que des caractères uniques, ils semblent fonctionner de la même manière.
Nacht - Rétablir Monica

Réponses:

43

Les deux sont assez différents.

a[bc]dest un modèle de nom de fichier (dans des shells autres que fish). Il s'étendra aux deux noms de fichiers abd et acds'il s'agit de noms de fichiers existants dans le répertoire en cours.

  • La [...]partie est une expression entre crochets qui correspond à un seul caractère parmi ceux répertoriés (ou les éléments de classement lorsque des plages sont incluses). Pour faire correspondre le modèle a[bc]d, le caractère entre les chaînes aet ddans un nom de fichier doit être a bou a c.

  • S'il abdexiste, mais acdn'existe pas, alors il ne ferait que s'étendre à abd, et vice versa.

  • Si ni abd, ni acdexister, en fonction de la coquille et les options, il déclencherait une erreur (Unix d' origine sh, (t)csh, zsh, fish, bash -O failglob) et peut - être sortir de la coquille, ou laisser le motif unexpanded¹ (Bourne-like et rc-comme coquilles) ou étendre à rien ( bash/zsh/yash -o nullglob, certaines anciennes versions de fish, Unix d'origine shet (t)cshs'il y a d'autres globs correspondants dans la même commande).

a{b,c}dest une extension d'accolade (dans des coquilles qui les supportent). Il s'étendra aux deux chaînes abd et acd.

  • La {...}pièce est un ensemble délimité par des virgules des chaînes (dans cet exemple, dans certains obus, il peut également être une plage telle que a..kou 20..25ceux ou plus avancés comme 00..20..2ou 0..20..2%02d), et l'expansion est calculée en combinant chacun de ces chaînes avec le flanquante cordes aet d. Ces chaînes peuvent être plus longues qu'un seul caractère et peuvent également être des extensions d'accolade elles-mêmes.

  • L'expansion se produit indépendamment du fait que ces chaînes correspondent ou non aux noms de fichiers existants.

Si vous construisez des chaînes, utilisez une extension d'accolade. Si vous faites correspondre des noms de fichiers, utilisez un modèle de nom de fichier.


¹ Dans ce cas particulier, il a[bc]dpeut arriver que ce soit le nom d'un fichier existant, c'est pourquoi il est potentiellement dangereux d'utiliser des choses comme rm -f ./*.[ch]celles-ci et rm -f ./*.{c,h}c'est moins un problème.

Kusalananda
la source
Merci d'avoir clarifié "Si abd existe, mais acd n'existe pas, alors il ne s'étendrait qu'à abd". Je suppose que c'est ce qui manque dans ma réponse.
Weijun Zhou
9
Une autre différence cruciale est que dans a{b,c}d, les parties bet cn'ont pas besoin d'être des lettres simples; par exemple ex{ten,ci}sion. Alors que ex[tenci]sionou quoi que ce soit ne correspondra qu'à l' une de ces lettres.
alexis
7

a[bc]dcorrespond au modèle et fait partie de la norme POSIX. Dans POSIX, ceci est introduit comme "expression de parenthèse de modèle". Il est documenté dans la section 2.13 du manuel

Lorsqu'ils ne sont pas entre guillemets et en dehors d'une expression entre crochets, les trois caractères suivants ont une signification particulière dans la spécification des modèles:

    ?
      Un point d'interrogation est un modèle qui doit correspondre à n'importe quel caractère.
    *
      Un astérisque est un modèle qui doit correspondre à plusieurs caractères, comme décrit dans Modèles correspondant à plusieurs caractères.
    [
      La parenthèse ouverte doit introduire une expression de parenthèse de modèle.

La section 2.13.3 mentionne également quelque chose qui se comporte différemment de ce à quoi on pourrait s'attendre pour les expressions rationnelles habituelles quand il est utilisé pour l'expansion du nom de fichier (c'est moi qui souligne)

Les règles décrites jusqu'à présent dans Motifs correspondant à un seul caractère et Motifs correspondant à plusieurs caractères sont qualifiées par les règles suivantes qui s'appliquent lorsque la notation de correspondance de motifs est utilisée pour l'expansion du nom de fichier:

Le caractère barre oblique dans un nom de chemin doit être explicitement mis en correspondance en utilisant une ou plusieurs barres obliques dans le modèle; il ne doit correspondre ni à l'astérisque ni aux caractères spéciaux de point d'interrogation, ni à une expression entre crochets. Les barres obliques dans le modèle doivent être identifiées avant les expressions entre crochets; ainsi, une barre oblique ne peut pas être incluse dans une expression de crochet de modèle utilisée pour l'expansion du nom de fichier. Si un caractère barre oblique est trouvé après un caractère de crochet ouvert non échappé avant qu'un crochet carré de fermeture correspondant ne soit trouvé, le crochet ouvert doit être traité comme un caractère ordinaire. Par exemple, le modèle "a[b/c]d"ne correspond pas à des noms de chemin tels que abdou a/d. Il ne correspond qu'à un nom de chemin littéralement a[b/c]d.

a{b,c}dest l' expansion des accolades , ce n'est pas dans la spécification de POSIX. Voici la partie correspondante du manuel bash (souligné par moi):

L'expansion d'accolade est un mécanisme par lequel des chaînes arbitraires peuvent être générées. Ce mécanisme est similaire à l' extension de nom de fichier (voir Extension de nom de fichier), mais les noms de fichiers générés n'ont pas besoin d'exister . Les modèles à développer entre accolades prennent la forme d'un préambule facultatif , suivi soit d'une série de chaînes séparées par des virgules, soit d'une expression de séquence entre une paire d'accolades, suivie d'un post-scriptum facultatif . Le préambule est préfixé à chaque chaîne contenue dans les accolades, et le post-scriptum est ensuite ajouté à chaque chaîne résultante, s'étendant de gauche à droite.

Selon le commentaire de @mosvy, cela est apparu pour la première fois, cshmais le comportement dans bashest différent de cshet d'autres coquilles. Ce type d'expansion de croisillons est également présent dans glob(3).

Il existe un autre type d'expansion d'accolades {a..z}qui n'apparaît qu'après bash3.0, et il y en a d'autres ajoutées dans bash4.0.

Dans un shell où la globalisation est activée, exécutez dans un dossier vide, le résultat suivant est retourné

$ echo a[bc]d
a[bc]d
$ echo a{b,c}d
abd acd

En réponse au commentaire de @ Jesse_b, si vous êtes dans un shell interactif et que les deux s'appliquent, il a[bc]dest moins difficile de taper. Par exemple grep pattern [ab][12].txt.

Weijun Zhou
la source
2
L'expansion de l'accolade n'est pas un "bashisme"; il est apparu pour la première fois cshbien avant bash. Il est également présent dans la fonction de bibliothèque glob (3). La différence est que dans bashelle est effectuée avant les autres extensions: a=A; ab=A/B; ac=A/C; echo $a{b,c}fonctionnera dans bash différemment de tout autre shell.
mosvy
Merci. Je mettrai à jour la réponse.
Weijun Zhou