1. ホーム
  2. bash

[解決済み] Bashのwhileループに入力をパイプし、ループ終了後も変数を保持する方法

2023-02-17 11:35:04

質問

Bashで使用できる cat <(echo "$FILECONTENT")

Bashでも使用可能です。 while read i; do echo $i; done </etc/passwd

を組み合わせて使うこともできます。 echo $FILECONTENT | while read i; do echo $i; done

最後のものの問題は、サブシェルが作成され、whileループが終了した後に変数 i はそれ以上アクセスできないことです。

質問です。

このようなことを実現するにはどうしたらよいでしょうか。 while read i; do echo $i; done <(echo "$FILECONTENT") または言い換えれば どうすれば i がループしていることを確認できますか?

whileステートメントを {} で囲むこともできますが、これでは問題が解決しません(関数内で while ループを使って i という変数を返したい場合を想像してみてください)。

どのように解決するのですか?

の正しい表記は プロセスの置換 です。

while read i; do echo $i; done < <(echo "$FILECONTENT")

の最後の値は i に代入された最後の値は、ループが終了したときに利用可能になります。 代替案としては

echo $FILECONTENT | 
{
while read i; do echo $i; done
...do other things using $i here...
}

中括弧はI/Oのグループ化操作であり、それ自体はサブシェルを作成しない。 この文脈では、パイプラインの一部であるため、サブシェルとして実行されますが、その理由は | ではなく { ... } . 質問でこのことに触れていますね。 AFAIK、あなたは関数の中でこれらの中からリターンを行うことができます。


Bashはまた shopt というビルトインがあり、その多くのオプションのひとつに

lastpipe

設定され、ジョブ制御がアクティブでない場合、シェルは現在のシェル環境でバックグラウンドで実行されていないパイプラインの最後のコマンドを実行します。

したがって、次のようなものを使用します。 をスクリプトで使用することができます。 を使うと、修正された sum をループの後に利用できるようにします。

FILECONTENT="12 Name
13 Number
14 Information"
shopt -s lastpipe   # Comment this out to see the alternative behaviour
sum=0
echo "$FILECONTENT" |
while read number name; do ((sum+=$number)); done
echo $sum

コマンドラインでこれを行うと、通常、「job control is not active」(つまり、コマンドラインでは、ジョブ制御がアクティブになっている)で反則となります。 スクリプトを使用せずにこれをテストすると、失敗します。

また、指摘されているように Gareth Rees は、彼の 回答 を使用することができます。 の文字列 :

while read i; do echo $i; done <<< "$FILECONTENT"

これには shopt を必要としないので、これを使ってプロセスを保存できるかもしれません。