Bash:teeを使用するforループの変数範囲

Bash:teeを使用するforループの変数範囲

考慮する:

numbers="1 111 5 23 56 211 63"
max=0

for num in ${numbers[@]}; do

      [ $num -gt $max ]\
           && echo "old -> new max = $max -> $num"\
           && max=$num

done | tee logfile

echo "Max= $max"

max変数を削除すると| tee logfile211として正しく印刷されますが、そのままにしてくださいMax= 0

どうしたの?

ベストアンサー1

パイプの各側面はサブシェルで実行されます。サブシェルは、同じ状態で開始し、独立して進化する元のシェルプロセスのコピーです。子シェルに設定された変数は、親シェルにエスケープできません。

Bashでは、パイプを使用する代わりに次のものを使用できます。プロセスの交換。ループが元のシェルとサブシェルteeでのみ実行されることを除いて、これはパイプとほぼ同じように動作します。

for num in "${numbers[@]}"; do
  if ((num > max)); then
    echo "old -> new max = $max -> $num"
    max=$num
  fi
done > >(tee logfile)
echo "Max= $max"

その間、スクリプトでいくつか変更しました。

パイプソリューションとサブシェルソリューションの間にはいくつかの違いがあります。パイプ処理されたコマンドは両方のコマンドが終了すると完了しますが、プロセス置換を含むコマンドはプロセス置換のプロセスを待たずに基本コマンドが終了すると完了します。これは、スクリプトの完了時にログファイルが完全に記録されていない可能性があることを意味します。

別のアプローチは、別のチャネルを使用してサブシェルから元のシェルプロセスに通信することです。あなたはできます一時ファイルの使用(柔軟ですが実行するのは難しいです。一時ファイルを適切なディレクトリに書き込み、名前の競合を防ぎ(使用mktemp)、エラーが発生しても削除します。別のパイプを使用してください結果を渡し、コマンド置換によって結果を取得します。

max=$({ { for … done;
          echo "$max" >&4
        } | tee logfile >&3; } 4>&1) 3&>1

出力はteeファイル記述子3に移動し、これはスクリプトの標準出力にリダイレクトされます。の出力はecho "$max"ファイルディスクリプタ4に移動し、これはコマンドの代わりにリダイレクトされます。

おすすめ記事