546 votes

Pourquoi les espaces blancs sont-ils parfois nécessaires autour des métacaractères ?

Il y a quelques mois, j'ai tatoué un bombe à fourche sur mon bras, et j'ai sauté les espaces, parce que je pense que c'est plus joli sans eux. Mais à mon grand désarroi, parfois (pas toujours) quand je l'exécute dans un shell, il ne démarre pas une bombe fork, mais il donne juste une erreur de syntaxe.

bash: syntax error near unexpected token `{:'

Hier, c'est arrivé quand j'ai essayé de l'exécuter dans la voiture d'un ami. Bash puis j'ai ajouté l'espace et ça a soudainement fonctionné, :(){ :|:& };: au lieu de :(){:|:&};:

Les espaces ont-ils une importance ? Me suis-je tatoué une erreur de syntaxe sur le bras ?!

Cela semble toujours fonctionner dans zsh mais pas dans Bash.

Une question connexe n'explique rien au sujet des espaces, ce qui est vraiment ma question ; Pourquoi l'espace blanc est-il nécessaire pour que Bash puisse l'analyser correctement ?

6 votes

J'ai posté la même question aquí (à l'exception de la partie tatouage).

3 votes

De même, les deux points ( :) ne peuvent pas être utilisés comme nom de fonction (voir : pubs.opengroup.org/onlinepubs/9699919799/utilités/ ) ... Le /bin/sh de FreeBSD donne même une erreur à ce sujet ...

5 votes

@Carpetsmoker : Je ne vois pas en quoi c'est pertinent. Cette question concerne Bash.

270voto

Dmitri Chubarov Points 4518

Il existe une liste de caractères qui séparent les jetons en BASH. Ces caractères sont appelés métacaractères et ils sont | , & , ; , ( , ) , < , > , espace y onglet . Par contre, les accolades ( { y } ) sont des caractères ordinaires qui composent les mots.

Omettre le deuxième espace avant } fera l'affaire, puisque & est un métacaractère. Par conséquent, votre tatouage doit comporter au moins un caractère d'espace.

:(){ :|:&};:

36 votes

Solution facile : déplacer la première partie du taoo vers la gauche et transplanter de la peau entre les deux parties.

23 votes

J'ai aimé le terme, on the other hand ... un jeu de mots ? ;) :D (Désolé, pour le commentaire hors sujet.)

4 votes

Mais c'est différent pour zsh ? En quoi zsh est-il différent ?

83voto

SzG Points 4468

Il suffit de tatouer un

#!/bin/zsh

au-dessus et vous serez bien.

6 votes

Si nous sommes pointilleux, le shebang ne fonctionnerait pas du tout, car le shell, avec un peu de chance zsh, est en mode interactif, comme le montre l'invite...

50voto

Peter Westlake Points 2625

Les accolades ressemblent davantage à des mots-clés bizarres qu'à des symboles spéciaux, et nécessitent des espaces. C'est différent des parenthèses, par exemple. Comparez :

(ls)

qui fonctionne, et :

{ls}

qui cherche une commande nommée {ls} . Pour fonctionner, il faut qu'il le soit :

{ ls; }

Le point-virgule permet d'éviter que l'accolade fermante ne soit prise comme paramètre par l'utilisateur. ls .

Il suffit de dire aux gens que vous utilisez une police proportionnelle avec un caractère d'espacement plutôt étroit.

0 votes

Alfe : non, ce n'est pas une déclaration composée.

12 votes

@DmitriChubarov - c'est une astuce très sournoise, utilisant une signification complètement différente des accolades. Il développe la liste de valeurs séparées par des virgules, qui, dans ce cas, est juste le fichier ls .

0 votes

Je faisais juste l'idiot. Ne prenez pas mon dernier commentaire trop au sérieux ;-)

41voto

Jerry Coffin Points 237758

Bien qu'elle ne soit pas facilement visible dans la police du tatouage, il existe en fait une marque d'ordre d'octet (BOM) entre l'accolade et les deux points (vous avez peut-être été suffisamment intoxiqué lorsque vous vous êtes fait tatouer pour ne pas la remarquer, mais elle est bien là). Il reste donc trois possibilités évidentes :

  1. Vous avez omis de saisir la nomenclature lorsque vous avez transcrit le code. Le résultat est une application évidente de GIGO. Le shell ne reconnaît tout simplement pas une nomenclature qui n'est pas présente dans votre transcription ratée.
  2. Votre coquille est trop vieille. Il ne reconnaît pas les caractères Unicode, donc la nomenclature (et probablement tous les autres caractères Unicode) est complètement ignorée, même si une nomenclature située n'importe où, sauf au début d'un fichier, est censée être traitée comme un espace de largeur nulle, sans coupure.
  3. Votre coquille est trop récente. L'utilisation d'une nomenclature comme ZWNBS est dépréciée, et les auteurs ont mis en place une future version d'Unicode dans laquelle cette utilisation n'est plus autorisée.

40voto

devnull Points 45016

et puis j'ai ajouté les espaces et ça a soudainement marché ...

C'est à cause de la façon dont le shell analyse les données. Vous avez besoin d'un espace après le début de la définition de la fonction, c'est-à-dire après l'élément { .

foo() { echo hey& }
foo() { echo hey&}
foo(){ echo hey&}

sont valides. D'autre part,

foo() {echo hey&}

ne l'est pas.


Tu as vraiment besoin d'un tatouage comme celui-ci :

enter image description here


De la source :

  /* We ignore an open brace surrounded by whitespace, and also
     an open brace followed immediately by a close brace preceded
     by whitespace.  */

Omettre un espace après le { provoque le {echo pour être interprété comme un seul jeton.


Une forme équivalente de

:(){ :|:& };:

serait

:(){
:|:& };:

Notez qu'il n'y a pas d'espace après { dans la version alternative, mais un saut de ligne permet au shell de reconnaître { comme un jeton.

0 votes

"L'omission d'un espace après le { fait que le {echo est interprété comme un seul token." -- donc l'analyseur croit-il avoir rencontré une commande appelée {echo avant d'avoir atteint une accolade d'ouverture requise ?

0 votes

LOL. Cette photo, c'est mon cou :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X