Für Schleifen in zsh und bash

57

Ich habe festgestellt, dass es in zsh zwei alternative Möglichkeiten zum Erstellen von Schleifen gibt :

  1. for x (1 2 3); do echo $x; done
  2. for x in 1 2 3; do echo $x; done

Beide drucken:

1
2
3

Meine Frage ist, warum die beiden Syntaxen? Ist $xIterieren durch eine andere Art von Objekt in jedem von ihnen?

Macht bash einen ähnlichen Unterschied?

Nachtrag:

Warum funktioniert folgendes ?:

#!/bin/zsh
a=1
b=2
c=5    

d=(a b c)    
for x in $d; do print $x;done

aber dieser nicht ?:

#!/bin/zsh
a=1
b=2
c=5

d=(a b c)    
# It complains with "parse error near `$d'"
for x $d; do print $x;done 
Amelio Vazquez-Reina
quelle
5
Für das Beispiel "does not work", das ein csh- Stil für Schleifen ist, fehlen die Klammern. for x ($d); do print $x; donewird funktionieren, und es wird mit der ersten Syntax übereinstimmen, die Sie am Anfang Ihrer Frage aufgezählt haben.
Tim Kennedy
1
Es ist so verrückt, dass diese beiden Aussagen in der Tat nicht "gleich funktionieren". Ich kann es buchstäblich nicht verstehen! Ich muss einiges von dem rauchen, was diese Shell-Designer damals rauchten, lol.
Alex Gray
Vorsichtig, es gibt mehr in dieser Geschichte, als zunächst erscheint. Ich lade Sie ein, meine Antwort zu überprüfen.
Jasonleonhard
Ich habe niemanden gesehen, der es erwähnt hat, aber beide Formen erlauben das Weglassen von do / done: for i ({0..4..2}) for j ({a..c}) echo "($i,$j)"= {0,2,4}x{a,b,c}. Semikolons gelten für die äußerste Schleife und Umleitungen gelten für die innerste Schleife. Wenn Sie dies ändern müssen, benötigen Sie nur geschweifte Klammern: for i ({0..4..2}) { for j ({a..c}) echo "($i,$j)" } | cat -n= {1,...,9}*({0,2,4}x{a,b,c}). Natürlich können Sie Schleifen mit zsh-Erweiterung kombinieren:for i ("("{0..4..2}","{a..c}")") echo $i
John P

Antworten:

58

Verschiedene Formen komplexer Befehle wie Schleifen haben in zsh alternative Formen . Diese Formen sind größtenteils von der C-Schale inspiriert , die in jungen Jahren ziemlich verbreitet war, jetzt aber verschwunden ist. Diese alternativen Formen verhalten sich genauso wie die normalen Formen, sie haben nur eine andere Syntax. Sie sind etwas kürzer, aber weniger klar.

Das Standardformular für den forBefehl lautet for x in 1 2 3; do echo $x; doneund das Standardformular für den whileBefehl lautet while test …; do somecommand; done. KSH, bash und zsh haben eine alternative Form von for: for ((i = 0; i < 42; i++)); do somecommand; done, die die nachahmt forSchlingen Sprachen wie Pascal oder C, auf ganze Zahlen aufzuzählen. Andere exotische Formen, die in zsh vorkommen, sind spezifisch für zsh (aber oft von csh inspiriert).

Gilles 'SO - hör auf böse zu sein'
quelle
Vielen Dank @Guilles. Ich bin immer noch ein bisschen verwirrt. Um welche Form handelt es sich zsh? Außerdem habe ich am Ende meines OP ein Beispiel hinzugefügt, in dem ich nicht herausfinden kann, wie ich zwischen den Syntaxen übersetzen soll. Wenn der Unterschied nur in der Syntax besteht, wie soll ich das zweite Skript im Addendum korrigieren, damit es funktioniert?
Amelio Vazquez-Reina
3
@intrpc Siehe meine aktualisierte Antwort. Das letzte Beispiel funktioniert nicht, weil Sie geschrieben haben for x $dund zsh erwartet, dass entweder inoder (wo Sie geschrieben haben $d. Satzzeichen und reservierte Wörter können nicht aus einer Variablenerweiterung stammen. Sie müssen analysiert werden, bevor die Shell mit den Variablenerweiterungen beginnen kann.
Gilles 'SO - hör auf böse zu sein'
@intrpc sind beide zsh-spezifisch. zsh wurde speziell entwickelt, um sowohl die Bourne-, Korn- als auch die C-Shell-Syntax zu unterstützen, da es sich um eine Mischung aus allen dreien handelt.
Tim Kennedy
1
@pseyfert Es funktioniert, hat aber keinen Vorteil gegenüber den von mir gezeigten Formularen: Es ist weniger portabel als das for (( … ))Formular und belegt viel Speicher, wenn 3 groß ist.
Gilles 'SO- hör auf böse zu sein'
1
@ alpha_989 In sh-ähnlicher Syntax brauchst du doafter ));. Zsh akzeptiert auch eine andere Syntax, for ((…)); COMMANDbei der COMMANDes sich um einen einzelnen Befehl handelt. Deshalb akzeptiert es for ((i = 1; i<100; i++)); ghi show $i | grep "log". Wenn es danach sieht done, beschwert es sich, weil es kein doEnde gab. Siehe „Alternative Formulare für komplexe Befehle“ im Handbuch .
Gilles 'SO- hör auf böse zu sein'