バックグラウンド変数の割り当てと待機コマンドの理解

バックグラウンド変数の割り当てと待機コマンドの理解

内容man bashは次のとおりです。

ちょっと待って [-fn] [ID...]

指定された各子プロセスを待って終了ステータスを返します。各IDはプロセスIDでもジョブ仕様でもかまいません。ジョブ仕様が指定されると、そのジョブのパイプライン内のすべてのプロセスが待機します。 IDが指定されていない場合は、現在アクティブなすべての子プロセスが待機し、状態0が返されます。 -nオプションが指定されている場合、waitはジョブが終了するのを待ってから終了ステータスを返します。

典型的な例は次のとおりです。

 command1 & command2 & command3 & wait

つまり、これら3つのコマンドは並列に実行され、すべてのコマンドが完了した後にのみ、次のステップが完了します。

私の問題は、次の2つのbashスクリプトの結果です。

#!/bin/bash
for i in 1 2 3 ; do
  a=$i
  echo "$a is $i"
done 2>/dev/null

結果:

1 is 1
2 is 2
3 is 3

私が期待したものとほぼ同じです。今、変数を割り当てることは長いプロセスであると仮定し、それを待ちます。

#!/bin/bash
  for i in 1 2 3 ; do
  a=$i & wait
  echo "$a is $i"
done 2>/dev/null

結果:

3 is 1
3 is 2
3 is 3

私は次の理由で混乱しています。

  1. 完了するまで待つ必要がある唯一のwaitプロセスは変数を割り当てることで、次のスクリプトの次のステップ(echo)を実行する必要があります。a=3ループの最後の反復でのみ発生する必要があります。
  2. 私が知る限り、for-loopsはサブシェルで実行され、waitそれを起動したシェルの範囲のみを持ちます。したがって、for-loopが完了するまで待ってはいけません(これが親エントリなので)。
  3. 私はecho他のプロセスと並行して実行することを指定しなかったので、競合状態を予想しませんでした。

それでは、a最後のループ反復で-variableが設定されていますが、この変数が$i設定されていないのはなぜですか?wait私は命令のどの部分を間違って理解しましたか?この行動は私の期待を完全に超えました。

5.7.0-0.bpo.2-amd64 Linuxカーネルに基づくGNU bash、バージョン5.0.3(1)。

プリセットをオフにすると、a2番目のスクリプトはこの値を返します。

 is 1
 is 2
 is 3

つまり、変数が設定されておらず、以前の実行からドラッグされました。

ベストアンサー1

forループはサブシェルでは実行されません。たとえば、変数がループ外で使用されている場合でもfor i in 1 2 3; do a=foo; done; echo $a印刷できます。fooループ変数の値は、ループによって割り当てられた最後の値でもあります(ループが終了すると最後の値ではない可能性がありますbreak)。

しかし、使用& するコマンドをサブシェルに入れてから操作を実行すると、割り当てはサブシェルa=$i &でのみ発生します。もちろん、サブシェルで割り当てられた値を使用することもできます。

たとえば、

a=1;
{ a=2; echo "subshell: $a"; } &
echo "main: $a";
wait;
echo "after: $a"

印刷されます

main: 1
subshell: 2
after: 1

検証などの操作を実行してください{ a=$i; echo "$a"; } &

バックグラウンドコマンドがメインシェルの変数にアクセス(および変更)するようにするには、プロセス間のいくつかの同期が必要であり、これは潜在的に比較的小さな利得のためにシェルを複雑にします。

もしあなたならするたとえば、バックグラウンドで長期実行コマンドを実行したいが出力が必要な場合は、出力を一時的にファイルに保存するなどの作業を実行する必要があります。

tmp=$(mktemp -d)
some long process > "$tmp/a" &
another long process > "$tmp/b" &
wait
a=$(< "$tmp/a")
b=$(< "$tmp/b")
...
rm -rf "$tmp"

または、コマンドを並列に実行するために特別に作成されたGNU Parallelのようなものを使用してください。parsetシェル変数に値を割り当てることができるコマンドもあります。

ループのすべての反復3でこれを得る理由は、おそらく以前に最初のループを実行して去ったからです。後続のすべての割り当てがサブシェルにプッシュされた後、これはループ全体でプライマリシェルに保持される値です。$aa3a

おすすめ記事