Dans certains cas, le nombre d'espaces importe dans les scripts bash (ou autres shell)

14

On m'a dit que les espaces sont importants dans bashou d'autres scripts shell et je ne devrais pas changer l'existence des espaces à moins de savoir ce que je fais. Par "changer l'existence", j'entends soit insérer un espace entre deux caractères non spatiaux, soit supprimer un espace entre deux caractères non spatiaux, par exemple en changeant var="$val"pour var ="$val"ou vice versa. Je veux demander

Existe-t-il des cas dans lesquels l'utilisation d'un seul espace ou l'utilisation de plusieurs espaces consécutifs dans un script shell fait une différence? .

(Bien sûr, l'insertion / la suppression d'un espace entre guillemets fait une différence, comme passer de echo "a b"à echo "a b"ou vice versa. Je cherche des exemples autres que cet exemple trivial.)

J'ai rencontré cette question, mais celle-ci concerne l'ajout et la suppression d'espaces entre deux caractères non spatiaux pour lesquels je connais de nombreux exemples qui feraient une différence.

Toute aide serait appréciée. Inclure plus de variétés de coquilles si possible.

Weijun Zhou
la source

Réponses:

19

En dehors des guillemets, le shell utilise des espaces (espaces, tabulations, retour à la ligne, retour chariot, etc.) comme séparateur de mots / jetons. Cela signifie:

  • Les choses non séparées par des espaces sont considérées comme un "mot".
  • Les éléments séparés par un ou plusieurs espaces sont considérés comme deux (ou plusieurs) mots.

Le nombre réel de caractères d'espacement entre chaque "chose" n'a pas d'importance, tant qu'il y en a au moins un.

cas
la source
Je vous remercie. Je ne trouve pas de contre-exemple moi-même. Je veux juste être certain.
Weijun Zhou
2
Bash considère également les flux de formulaires et les onglets verticaux comme des espaces.
fpmurphy
vrai. à l'origine, j'ai écrit «... newlines, etc», puis je l'ai changé pour ajouter explicitement des retours chariot. accidentellement laissé tomber le «etc».
cas
Que faire si le nombre d'espaces est si grand que le programme ne peut pas tenir en mémoire?
Worse_Username
7
@Worse_Username L'espace ne doit pas tenir en mémoire. Je viens de créer un script de 48 Go sur une machine avec 8 Go de RAM et 20 Go de swap. Ça s'est très bien passé. Il a fallu 3 minutes pour parcourir tous ces espaces, mais à la fin, il a réussi à exécuter une echocommande avec autant d'espace entre la commande et l'argument.
kasperd
23

C'est probablement de la triche, mais ceci:

rm foo\ bar         # "delete the file named 'foo bar'"

est différent de cela:

rm foo\  bar        # "delete the files named 'foo ' and 'bar'"

même si les espaces ne sont pas entre guillemets. ;-)

Plus confusément, ceci:

rm \
    foo          # "delete the file named 'foo'"

est différent de cela:

rm \ 
    foo          # "delete the file named ' ', then run the command 'foo'"

même s'ils ont l' air identiques!

ruakh
la source
Même si les espaces ne sont pas entre guillemets, la barre oblique inverse est fonctionnellement similaire à la forme des guillemets et je mettrais cela dans la même catégorie que "l'exemple trivial" de la question. (C'est intéressant cependant.)
David Z
12

Si on ne parle pas le caractère d'espace ( U+0020), mais tout caractère espaces ( U+0020, \n, \t, etc.), un cas particulier viennent à l' esprit: Voici les documents.

Ce code (en utilisant des espaces):

cat <<- 'EOF'
<space><space>foo
EOF

Imprime:

  foo

Mais ce code (à l'aide d'onglets):

cat <<- 'EOF'
<tab><tab>foo
EOF

Imprime:

foo

En effet ( comme l'indique POSIX ):

Si l'opérateur de redirection est <<-, tous les caractères <tab> en tête doivent être supprimés des lignes d'entrée et de la ligne contenant le délimiteur de fin.

nxnev
la source
1
C'est intéressant. J'ai pensé ici aux documents mais je ne connaissais pas l' <<-opérateur. Merci beaucoup.
Weijun Zhou
ici, les documents sont une forme de texte cité, pas un code shell. le fractionnement de mots du shell ne s'applique pas.
cas
2

Il a également un effet lors de l'écriture des instructions d'affectation. Comme si je dis que FOO=xyzcela va créer une variable d'environnement nommée FOOavec valeur xyz, mais si je sépare les égaux avec un espace, il pensera que j'invoque un programme nommé FOOavec l'argument =xyz. Il importe donc quand il s'agit de certaines syntaxes.

HSchmale
la source
Crée généralement FOO=xyzune variable de shell interne mais pas une variable d'environnement. Vous en avez besoin set -aou export FOO=xyzpour cela (c'est-à-dire en faisant partie de l'environnement des sous-processus non sous-shell).
Hauke ​​Laging du