Eine Antwort wieDaserklärt gut, wie man das Passspiel kontrolliertalleVariablen bis hin zu einem Befehl.
Ich wollte herausfinden, wie dies für jedes Argument einzeln durchgeführt werden kann. Beachten Sie (dies wurde in getestet zsh
):
$ program() { echo 1: $1 2: $2 3: $3; }
$ run() { program "$@"; }
$ run2() { echo `run $1`; }
$ run2 'a b' c
1: a b 2: 3:
Ich möchte einen Weg finden, ein erstes Argument zu übergeben, das eine Zeichenfolge mit Leerzeichen ist, und diesen gespleißten $@
Stil in einen anderen Befehl zu übernehmen. run2 "a b" c
sollte beispielsweise Folgendes erzeugen :1: a 2: b 3:
An diesem Punkt habe ich mein unmittelbares Problem gelöst, denn obwohl mein Testcode beim Testen in zsh abbricht, funktioniert er, sobald er in ein echtes Bash-Skript implementiert wurde.
Dies deutet darauf hin, dass dies möglicherweise auf einigen Feinheiten bei der Verarbeitung von Zeichenfolgen und Argumenten beruht, die nicht „sicher“ sind. Dies ist also eher eine Bitte um Kommentare zu einer robusteren Methode, um dieses Verhalten zuverlässig zu erreichen.
Antwort1
Der Unterschied zwischen Bash und Zsh, der hier von Bedeutung ist, liegt in der Art und Weise run2
der Aufrufe run
, insbesondere in der Auswirkung, wenn $1
Anführungszeichen weggelassen werden.
- In zsh
run $1
wird der Operator „remove-if-empty“ auf angewendet$1
, d. h. ruftrun
mit dem ersten Argument auf, das an übergeben wurderun2
, außer dass, wenn das erste Argument anrun2
leer war (oder wennrun2
ohne Argument aufgerufen wurde), dannrun
ohne Argument aufgerufen wird. - In anderen Shells im Bourne-Stil, wie z. B. Bash,
run $1
wird der Operator „split+glob“ auf angewendet$1
, d. h., es wird das erste Argumentrun2
in durch Leerzeichen getrennte Blöcke¹ aufgeteilt, jedes Stück wird als Platzhaltermuster² interpretiert und jedes Platzhaltermuster, das mit einer oder mehreren Dateien übereinstimmt, durch die Liste der Übereinstimmungen ersetzt.
Daher run2 'a b' c
werden Aufrufe run
mit dem Argument a b
in zsh durchgeführt (das Argument wird unverändert übergeben), Aufrufe run
mit den beiden Argumenten a
und b
in bash jedoch (aufgeteilt in durch Leerzeichen getrennte Teile).
Ich möchte einen Weg finden, ein erstes Argument zu übergeben, das eine Zeichenfolge mit Leerzeichen ist, und diesen gespleißten
$@
Stil in einen anderen Befehl zu übernehmen.run2 "a b" c
sollte beispielsweise Folgendes erzeugen :1: a 2: b 3:
Ihre Beschreibung und Ihr Beispiel sagen etwas anderes aus. Wenn Sie das erste Argument an den anderen Befehl übergeben möchten, verwenden Sie , run "$1"
um sicherzustellen, dass das Argument nicht aufgeteilt wird. Das Übergeben unveränderter Argumente ist der ganze Sinn von "$@"
.
Es scheint, dass Sie eigentlich das erste Argument in durch Leerzeichen getrennte Blöcke aufteilen möchten run2
. In Bash können Sie dies tun, indem Sie die Platzhaltererweiterung deaktivieren und dann (vorausgesetzt, dies IFS
hat sich gegenüber der Standardeinstellung nicht geändert) eine Erweiterung ohne Anführungszeichen verwenden.
run2 () ( set -f; run $1; )
( echo "$(somecommand)"
ist im Wesentlichen gleichbedeutend mit der Ausführung somecommand
in einer Subshell, und es scheint, dass Sie dies gemeint haben und nicht „ echo $(somecommand)
which wendet split+glob auf die Ausgabe des Befehls an, daher habe ich die redundante Echo-Befehlsersetzung entfernt.)
In zsh können Sie das =
Zeichen in einer Parameterersetzung verwenden, um eine Weltaufteilung (und kein Globbing) für den Wert durchzuführen.
run2 () { run $=1; }
Die Syntax von zsh ist nicht mit der von einfachem sh kompatibel. Wenn Sie ein sh-Skript aus zsh beziehen möchten, können Sie das emulate
folgende Build verwenden:
emulate sh -c '. myscript.sh'
Wird verwendet emulate ksh
, um (einige Funktionen von) ksh zu emulieren. Dies emuliert nicht alle Bash-Funktionen, ermöglicht Ihnen jedoch die Verwendung von Arrays.
¹ Allgemeiner gesagt, basierend auf dem Wert von IFS
.
² Sofern dies nicht mit deaktiviert wurde set -f
.
Antwort2
Willkommen in der Welt des Zitierens und der Zitatüberraschungen.
Das Hauptproblem besteht darin, dass zsh
standardmäßig keine Aufteilung bei IFS-Zeichen erfolgt.
Darin unterscheidet es sich von allen anderen Shells.
Um zu testen, wie Anführungszeichen die Funktionsweise von Shells ändern, benötigen wir Code, der sowohl die in Anführungszeichen gesetzten als auch die nicht in Anführungszeichen gesetzten Versionen Ihres Codes testet.
Ihr Code (mit Hinzufügen einiger Variablen):
program() { printf '%02d-1: %6s 2: %6s 3: %6s' "$i" "$1" "$2" "$3"; }
runa() { program "$@" ; }
run1() { echo "`runa $1 $2 $3 `"; }
run1 'a b' c
Lassen Sie mich näher auf die Einzelheiten eingehen.
Nehmen wir an, Sie erstellen einen lokalen sh
Link, der auf den zsh
Wohnort verweist:
ln -s "/usr/bin/zsh" ./sh
Und nehmen wir außerdem an, Sie kopieren das folgende Skript in eine so
Datei.
Ein Skript, das jede Funktion mit in Anführungszeichen gesetzten und nicht in Anführungszeichen gesetzten Variablen wiederholt:
program() { printf '%02d-1: %6s 2: %6s 3: %6s' "$i" "$1" "$2" "$3"; }
runa() { program "$@"; }
runb() { program $@ ; }
run1() { echo "`runa "$1" "$2" "$3"`"; }
run2() { echo "`runb "$1" "$2" "$3"`"; }
run3() { echo "`runa $1 $2 $3`"; }
run4() { echo "`runb $1 $2 $3`"; }
for i in `seq 4`; do
run"$i" 'a b' c
done
Bei der Ausführung wird dann Folgendes ausgedruckt:
# Any shell (except zsh) results.
01-1: a b 2: c 3:
02-1: a 2: b 3: c
03-1: a 2: b 3: c
04-1: a 2: b 3: c
Nur der erste Lauf (run1), bei dem alles in Anführungszeichen steht, bleibt 'a b'
verbunden.
Allerdings verhält sich zsh immer so, als ob alles in Anführungszeichen gesetzt worden wäre:
# ZSH results.
01-1: a b 2: c 3:
02-1: a b 2: c 3:
03-1: a b 2: c 3:
04-1: a b 2: c 3:
zsh in der Emulation.
Es wird angenommen, dass zsh
ältere Shells emuliert werden, wenn es als sh
oder aufgerufen wird ksh
.
In der Praxis trifft dies jedoch nicht immer zu:
$ ./sh ./so # emulated sh
01-1: a b 2: c 3:
02-1: a b 2: c 3:
03-1: a 2: b 3: c
04-1: a 2: b 3: c
Die zweite Zeile unterscheidet sich von der zweiten Zeile jeder anderen Shell.
Es ist eine gute Idee,Lesen Sie die Antworten auf diese Frage