web-dev-qa-db-fra.com

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

Il y a quelques mois, j'ai tatoué une bombe fourchue sur mon bras et j'ai sauté les espaces blancs, car je pense que c'est plus joli sans eux. Mais à mon grand désarroi, parfois (pas toujours) quand je le lance dans un shell, cela ne déclenche pas un fork bombe, mais cela donne simplement une syntaxe Erreur.

bash: syntax error near unexpected token `{:'

Hier, c’est arrivé quand j’ai essayé de le lancer dans un shell Bash d’un ami, puis j’ai ajouté le blanc et cela a fonctionné, :(){ :|:& };: au lieu de :(){:|:&};:

Les espaces blancs sont-ils importants? ai-je tatoué une erreur de syntaxe sur mon bras?!

Il semble que cela fonctionne toujours dans zsh , mais pas dans Bash.

ne question connexe n'explique rien sur les espaces, ce qui est vraiment ma question; Pourquoi Bash doit-il disposer de l'espace nécessaire pour pouvoir l'analyser correctement?

538
spydon

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

L'omission du deuxième espace avant } suffira, car & est un métacaractère. Par conséquent, votre tatouage doit avoir au moins un caractère d'espace.

:(){ :|:&};:
266
Dmitri Chubarov

Juste un tatouage

#!/bin/zsh

Shebang dessus et tout ira bien.

80
SzG

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

(ls)

qui fonctionne, et:

{ls}

qui recherche une commande nommée {ls}. Pour travailler, il faut que:

{ ls; }

Le point-virgule empêche que l'accolade de fermeture soit prise en tant que paramètre pour ls.

Tout ce que vous avez à faire est de dire aux gens que vous utilisez une police proportionnelle avec un caractère espace plutôt étroit.

50
Peter Westlake

Bien que cela ne soit pas facilement visible dans la police tatoo, il existe en fait une marque Byte-Order (BOM) entre le corset et le côlon (vous avez peut-être été suffisamment intoxiqué lorsque vous avez obtenu le tatouage pour ne pas l'avoir remarqué, mais c'est vraiment là) . Cela laisse 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. Shell ne reconnaît tout simplement pas une nomenclature qui ne figure pas dans votre transcription échouée.
  2. Votre Shell est trop vieux. Il ne reconnaît pas les caractères Unicode, de sorte que la nomenclature (et probablement tous les autres caractères Unicode) est complètement ignorée, même si une nomenclature située à un endroit autre que le début d'un fichier est censée être traitée comme un espace insensible sans largeur. .
  3. Votre Shell est trop nouveau. L'utilisation d'une nomenclature en tant que ZWNBS est obsolète et les auteurs ont implémenté une version future d'Unicode dans laquelle cette utilisation n'est plus autorisée.
40
Jerry Coffin

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

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

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

sont valides. D'autre part,

foo() {echo hey&}

n'est pas.


Vous avez réellement 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.  */

Si vous omettez un espace après le {, le {echo sera interprété comme un simple jeton.


Une forme équivalente de

:(){ :|:& };:

serait

:(){
:|:& };:

Notez qu'il n'y a pas d'espace après { dans la version alternative, mais une coupure de ligne oblige le shell à reconnaître { comme un jeton.

40
devnull