web-dev-qa-db-ja.com

サブシェルから親シェルの変数を設定します

サブシェルから親シェルに変数を設定するにはどうすればよいですか?

a=3
(a=4)
echo $a
38
Matt Joiner

サブシェルの重要な点は、呼び出しセッションにdoes n'tが影響することです。 bashでは、サブシェルは子プロセスであり、他のシェルは異なりますが、サブシェルの変数設定は呼び出し元に影響しません。定義により。

サブシェルが必要ですか?グループが必要な場合は、中括弧を使用します。

a=3
{ a=4;}
echo $a

4(そのスペースに注意してください)。または、変数値をstdoutに書き込み、呼び出し元でキャプチャします。

a=3
a=$(a=4;echo $a)
echo $a

バックティックを使用しないでください ``、それらは非推奨であり、読みにくい場合があります。

45
cdarke

Gdb-bash-variableハックがあります:

gdb --batch-silent -ex "attach $$" -ex 'set bind_variable("a", "4", 0)'; 

ただし、親スコープだけでなく、常にグローバルスコープ内の変数を設定します

31
BeniBela

あなたはしません。サブシェルは親の環境にアクセスできません。 (少なくともBashが提供する抽象化の範囲内では、gdbを使用したり、スタックを破壊したりするなどして、そのようなアクセスを密かに取得することができます。しかし、お勧めしません。)

1つの代替方法は、サブシェルが割り当てステートメントを、その親が読み取る一時ファイルに書き込むことです。

a=3
(echo 'a=4' > tmp)
. tmp
rm tmp
echo "$a"
21
ruakh

問題がwhileループに関連している場合、これを修正する1つの方法は、Process Substitutionを使用することです。

    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

10
marioquark

親スクリプトから呼び出されたスクリプトの変数を変更するには、「。」が前に付いたスクリプトを呼び出すことができます。

a=3
echo $a    
. ./calledScript.sh
echo $a

calledScript.shで

a=4

期待される出力

3
4
5
Carl Bosch

サブシェルで値を出力し、呼び出し元スクリプトの変数にサブシェル出力を割り当てることができます。

# 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以外)。

4
khachik

すべてのioをパイプに適用してファイルハンドルを使用できない限り、基本的な変数の更新は$(command)およびその他のサブプロセス内では不可能です。

ただし、通常のファイルは、通常の順次処理のための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」は、値が保存されるディレクトリです。私は速度と揮発性のためにラムディスクであることが好きです:

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ロジックを適用することも役立ちます。それ以外の場合は、まったく必要ありません。

猫の存在しないファイルエラーを回避するreadい読み取りメソッド:

v="$(cat "$aRam/globalVariable 2>/dev/null")"

この混乱のクールな機能は、プログラムの実行中に別のターミナルを開いてファイルの内容を調べることができることです。

0
Carmin