サブシェルから親シェルに変数を出力する

サブシェルから親シェルに変数を出力する

Bash は初めてで、ローカル/グローバル変数/サブシェルについてかなり混乱しています。変更された変数が関数の最後に出力されない理由がわかりません。ファイルの最後に最終行数とファイル数を出力しようとしていますが、そうすると、ローカル変数であるため 0 しか出力されません。変更された値を出力する方法はありますか?

count=0
files=0
find . -type f | while IFC= read -r file;
do
   let files=files+1
   wc -l $file
   count=$(($count+$(wc -l < $file)))
   echo "total lines $count ; total files $files"
done
echo $files $count
exit 0

答え1

はい。しかし、それはまったく直感的ではありません。たとえば、次のようにするとうまくいきます。

#!/bin/bash
count=0
files=0
while IFS= read -r file;
do
   let files=files+1
   wc -l $file
   count=$(($count+$(wc -l < $file)))
   echo "total lines $count ; total files $files"
done < <(find . -type f )
echo "$files $count"
exit 0

この<(command)構造は「プロセス置換」コマンドの出力を「ファイル」として扱うことができます。このようにループに入力すると、スクリプトが期待どおりに動作します。

問題はパイプ ( |) を使用しているため、while ループが別のサブシェルで実行され、その外部の変数を変更できなくなることです。

この機能をサポートしていないシェルでは<()、サブシェル内のパイプの右側にあるコマンドを実行し、そのサブシェルに最後のエコーを含めることができます。

#!/bin/bash
files=0
find . -type f | {
    while IFC= read -r file;
    do
        let files=files+1
        wc -l $file
        count=$(($count+$(wc -l < $file)))
        echo "total lines $count ; total files $files"
    done
    echo "$files $count"
}

exit 0

関連情報