サブシェル内で配列パラメータを変更する

サブシェル内で配列パラメータを変更する

shiftサブシェル内で配列パラメータに値を割り当てたり割り当てたりできますか?

サンプルコード:

arr=(a b c)
(shift arr)
echo $arr
# prints: a b c
# should print: b c

ベストアンサー1

これが現在のコピーでいくつかのコードを実行しているサブシェルの全体的なポイントです。シェル実行環境(詳しくは下記をご覧ください。POSIX仕様for sh)元の変数が保存されるため、要点は、サブシェルで行われたすべての変数の変更は、サブシェルが終了した後に失われることです。

従来、これはシェルがプロセスをフォークし、親プロセスが終了するのを待っている間に子プロセスでコードを実行することによって行われました。

POSIXはこれを義務付けておらず、ksh93は(...)サブシェルに戻るときにプロセスをフォークせずに元の環境を慎重に復元してサブシェルを実装します(時にはこれを正しく実行できない場合があります)。

zsh他のほとんどのシェルと同様に、この目的のためにプロセスが分岐します。(...)サブシェルがスクリプトの最後のコマンドである場合など、最適化には例外がありますzsh -c

$ 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

上記で実行されたプロセス21085と同じで、zshサブシェルを解釈して最後のpsコマンドを実行します。

aを設定するだけtrapでこの最適化を無効にできます。要点は、zshがサブシェルが返された後にシェルが何も実行しないことを保証できる場合にのみこれを実行することです。

子プロセスが親プロセスの変数値を変更するには、gdbプロセスに接続し、プロセスにコードを挿入してプロセスの内部メモリ構造を変更するなどのタスクを実行する必要があります。

サブシェルによって定義された配列の値を取得するには、その定義を親シェルに渡すサブシェルが必要です。たとえば、次のようにできます。

eval "$(
  # also a subshell using $(...)
  arr=( a b c )
  typeset -p arr
)"

その後、これはtypeset出力になりtypeset -a arr=( a b c )(またはtypeset -g -a arr=( a b c )関数内で呼び出された場合)、一度eval使用されると、親変数に同じ変数が生成されます。

ところで、代わりに:

shift arr

私は次を使うでしょう:

shift 1 arr

または:

arr[1]=()

このコードは、配列変数として宣言されているかどうかによって意味(vs)shift arrが異なるため、あいまいです。前者を使用すると、何が欲しいのかがより明確になります。shift 1 arrshift arr argvarrshift 1 arr

おすすめ記事