サブシェルから親シェルに変数を設定するにはどうすればよいですか?
a=3
(a=4)
echo $a
サブシェルの要点は、呼び出し側のセッションには影響しないということです。bashでは、サブシェルは子プロセスであり、他のシェルは異なりますが、それでもサブシェルの変数設定は呼び出し元に影響を与えません。定義により。
サブシェルが必要ですか?グループだけが必要な場合は、中かっこを使用してください。
a=3
{ a=4;}
echo $a
与える4
(その中のスペースに注意してください)。または、変数値をstdoutに書き込み、呼び出し元でキャプチャします。
a=3
a=$(a=4;echo $a)
echo $a
バックティックの使用は避けてください``、それらは非推奨であり、読みにくい場合があります。
gdb-bash-variableハックがあります:
gdb --batch-silent -ex "attach $$" -ex 'set bind_variable("a", "4", 0)';
これは、親スコープだけでなく、常にグローバルスコープに変数を設定しますが
あなたはそうしない。サブシェルは、その親の環境にアクセスできません。(少なくともBashが提供する抽象化の範囲内で、そのgdb
ようなアクセスを秘密裏に取得するために、スタックを使用したり、スタックを粉砕したりすることを試みる可能性があります。ただし、それはお勧めしません。)
1つの代替方法は、サブシェルが親が読み取るために一時ファイルに割り当てステートメントを書き込むことです。
a=3
(echo 'a=4' > tmp)
. tmp
rm tmp
echo "$a"
問題がwhileループに関連している場合、これを修正する1つの方法は、プロセス置換を使用することです。
var=0
while read i;
do
# perform computations on $i
((var++))
done < <(find . -type f -name "*.bin" -maxdepth 1)
ここに示されているように:https ://stackoverflow.com/a/13727116/2547445
親スクリプトから呼び出されたスクリプトの変数を変更するには、「。」を前に付けたスクリプトを呼び出すことができます。
a=3
echo $a
. ./calledScript.sh
echo $a
calledScript.shで
a=4
期待される出力
3
4
サブシェルに値を出力し、呼び出し元スクリプトの変数にサブシェル出力を割り当てることができます。
# subshell.sh
echo Value
# caller
myvar=$(subshell.sh)
サブシェルにさらに出力するものがある場合は、変数値と他のメッセージを別の出力ストリームにリダイレクトすることで分離できます。
# subshell.sh
echo "Writing value" 1>&2
echo Value
# caller
myvar=$(subshell.sh 2>/dev/null) # or to somewhere else
echo $myvar
または、サブシェルで変数の割り当てを出力し、呼び出し元のスクリプトでそれらを評価して、ファイルを使用して情報を交換しないようにすることもできます。
# subshell.sh
echo "a=4"
# caller
# export $(subshell.sh) would be more secure, since export accepts name=value only.
eval $(subshell.sh)
echo $a
私が考えることができる最後の方法は、終了コードを使用することですが、これは整数値の交換のみをカバーし(そして限られた範囲で)、終了コードを解釈するための規則を破ります(成功の場合は0、その他の場合は0以外)。
すべてのioをパイプに適用し、ファイルハンドルを使用できない限り、$(コマンド)およびその他のサブプロセス内で基本的な変数を更新することはできません。
ただし、通常のファイルは、通常の順次処理のためのbashのグローバル変数です。注:競合状態のため、この単純なアプローチは並列処理には適していません。
次のようなset/get/default関数を作成します。
globalVariable() { # NEW-VALUE
# set/get/default globalVariable
if [ 0 = "$#" ]; then
# new value not given -- echo the value
[ -e "$aRam/globalVariable" ] \
&& cat "$aRam/globalVariable" \
|| printf "default-value-here"
else
# new value given -- set the value
printf "%s" "$1" > "$aRam/globalVariable"
fi
}
「$aRam」は値が保存されるディレクトリです。私はそれがスピードとボラティリティのためのRAMディスクであることが好きです:
aRam="$(mktemp -td $(basename "$0").XXX)" # temporary directory
mount -t tmpfs ramdisk "$aRam" # mount the ram disk there
trap "umount "$aRam" && rm -rf "$aRam"" EXIT # auto-eject
値を読み取るには:
v="$(globalVariable)" # or part of any command
値を設定するには:
globalVariable newValue # newValue will be written to file
値の設定を解除するには:
rm -f "$aRam/globalVariable"
アクセス機能の唯一の本当の理由は、存在しないファイルを指定するとcatがエラーになるため、デフォルト値を適用することです。他のget/setロジックを適用することも役立ちます。そうでなければ、それはまったく必要ありません。
catの存在しないファイルエラーを回避する醜い読み取りメソッド:
v="$(cat "$aRam/globalVariable 2>/dev/null")"
この混乱のすばらしい機能は、プログラムの実行中に別の端末を開いてファイルの内容を調べることができることです。
親シェルから変数にアクセスする代わりに、コマンドの順序を変更し、プロセス置換を使用します。
a=3
echo 5 | (read a)
echo $a
プリント3
a=3
read a < <(echo 5)
echo $a
プリント5
もう一つの例:
let i=0
seq $RANDOM | while read r
do
let i=r
done
echo $i
vs
let i=0
while read r
do
let i=r
done < <(seq $RANDOM)
echo $i
または、ジョブ制御が非アクティブの場合(スクリプトなど)、lastpipe
シェルオプションを使用して、コマンドの順序を変更せずに同じ結果を得ることができます。
#!/bin/bash
shopt -s lastpipe
let i=0
seq $RANDOM | while read r
do
let i=r
done
echo $i
複数の変数を許可する非常に単純で実用的な方法は次のとおりですが、最終的には呼び出しにパラメーターを追加する可能性があります。
function ComplexReturn(){
# do your processing...
a=123
b=456
echo -n "AAA=${a}; BBB=${b};"
}
# ... this can be internal function or any subshell command
eval $(ComplexReturn)
echo $AAA $BBB
サブシェルから複数の変数を取得するのは困難ですが、グローバルを使用せずに関数内に複数の変数を設定できます。
変数の名前を、それをnamereflocal -n
と呼ばれる特別な変数に変換するために使用する関数に渡すことができます。
myfunc() {
local -n OUT=$1
local -n SIDEEFFECT=$2
OUT='foo'
SIDEEFFECT='bar'
}
myfunc A B
echo $A
> foo
echo $B
> bar
FOO=$(myfunc)
これは、サブシェルが複数の変数を設定する代わりに使用することになった手法です。