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 arr
shift arr argv
arr
shift 1 arr
答え2
サブシェルは別のプロセスであり、親プロセスを変更することはできません。