Array-Parameter innerhalb der Subshell ändern

Array-Parameter innerhalb der Subshell ändern

Ist es möglich, shifteinem 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).

zshfü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 -cSkript 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 psBefehl ausgeführt hat.

Es reicht aus, ein zu setzen, trapum 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 gdbzu 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 typesetwird 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 evalAusfü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 arrCodeabschnitt ist mehrdeutig, da er verschiedene Bedeutungen ( shift 1 arrvs shift arr argv) hat, je nachdem, ob arrer als Array-Variable deklariert ist oder nicht. Die Verwendung von shift 1 arrmacht deutlicher, dass Sie Ersteres wollen.

Antwort2

Eine Subshell ist ein anderer Prozess; sie kann den übergeordneten Prozess nicht ändern.

verwandte Informationen