Ist es möglich, shift
einem Array-Parameter innerhalb einer Subshell einen Wert zuzuweisen?
Beispielcode:
arr=(a b c)
(shift arr)
echo $arr
# prints: a b c
# should print: b c
Antwort1
Der Sinn von Subshells besteht darin, einen Teil des Codes in einer Kopie der aktuellenShell-Ausführungsumgebung(Einzelheiten siehedie POSIX-Spezifikationfür sh
), um die ursprüngliche zu erhalten. Der springende Punkt ist also, dass alle in der Untershell vorgenommenen Änderungen an Variablen nach der Beendigung der Untershell verloren gehen.
Traditionell geschieht dies dadurch, dass die Shell einen Prozess aufspaltet und den Code im untergeordneten Prozess ausführt, während das übergeordnete System auf dessen Beendigung wartet.
POSIX schreibt dies nicht vor und ksh93 implementiert zumindest (...)
Subshells, indem es bei der Rückgabe der Subshell die ursprüngliche Umgebung sorgfältig wiederherstellt, ohne einen Prozess zu verzweigen, wenn dies vermieden werden kann (obwohl dies in einigen Sonderfällen manchmal nicht richtig gelingt).
zsh
führt dafür wie die meisten anderen Shells einen Fork-Vorgang durch. Es gibt Ausnahmen zur Optimierung, beispielsweise wenn eine (...)
Subshell der letzte Befehl in einem zsh -c
Skript ist:
$ zsh -c 'zmodload zsh/system; echo $$; (echo $sysparams[pid]; ps; ps)'
21085
21085
PID TTY TIME CMD
1839 pts/4 00:00:00 zsh
21085 pts/4 00:00:00 zsh
21086 pts/4 00:00:00 ps
PID TTY TIME CMD
1839 pts/4 00:00:00 zsh
21085 pts/4 00:00:00 ps
Es handelt sich um denselben 21085-Prozess oben, der ausgeführt zsh
, die Subshell interpretiert und sogar den letzten ps
Befehl ausgeführt hat.
Es reicht aus, ein zu setzen, trap
um diese Optimierung ungültig zu machen. Der Punkt ist, dass dies nur durchgeführt wird, wenn zsh garantieren kann, dass nach der Rückkehr der Subshell nichts von der Shell ausgeführt wird.
Damit der untergeordnete Prozess den Wert einer Variablen im übergeordneten Prozess ändern kann, muss er beispielsweise eine Verbindung gdb
zu diesem Prozess herstellen und Code in ihn einfügen, um die internen Speicherstrukturen in diesem Prozess zu ändern.
Wenn Sie den Wert eines Arrays abrufen möchten, wie es von einer Subshell definiert wird, müssen Sie die Subshell so konfigurieren, dass sie ihre Definition an das übergeordnete Array weitergibt. Dies könnte beispielsweise folgendermaßen geschehen:
eval "$(
# also a subshell using $(...)
arr=( a b c )
typeset -p arr
)"
Anschließend typeset
wird eine Ausgabe typeset -a arr=( a b c )
(oder typeset -g -a arr=( a b c )
bei Aufruf innerhalb einer Funktion) ausgeführt, die nach eval
Ausführung dazu führt, dass die gleiche Variable im übergeordneten Element erstellt wird.
Übrigens statt:
shift arr
Ich würde ... benutzen:
shift 1 arr
oder:
arr[1]=()
Der shift arr
Codeabschnitt ist mehrdeutig, da er verschiedene Bedeutungen ( shift 1 arr
vs shift arr argv
) hat, je nachdem, ob arr
er als Array-Variable deklariert ist oder nicht. Die Verwendung von shift 1 arr
macht deutlicher, dass Sie Ersteres wollen.
Antwort2
Eine Subshell ist ein anderer Prozess; sie kann den übergeordneten Prozess nicht ändern.