次の方法でbash-4.2で配列を初期化しようとします。
ring=()
ls -las | tail -n +4 | while read line
> do
> ring+=("$line")
> echo ${ring[-1]}
> done
3924 -rw-r--r-- 1 username group 4015716 Mar 23 15:14 script.jar
4 -rw-r--r-- 1 username group 9 Feb 29 12:40 rec.lst
5541 -rw-r--r-- 1 username group 5674226917 Mar 28 15:25 debug.out
8 -rw-r--r-- 1 username group 6135 Mar 25 12:16 script.class
8 -rw-r--r-- 1 username group 6377 Mar 25 11:57 script.Java
8 -rwxr-xr-x 1 username group 4930 Mar 8 15:21 script-0.0.0.sh
8 -rwxr-xr-x 1 username group 6361 Mar 28 15:27 script-0.0.1.sh
echo ${ring[0]}
echo "${ring[0]}"
echo "${ring[@]}"
何が問題なのですか、ループの終了後に空の配列が表示されるのはなぜですか?
あなたの問題は、パイプライン(_command1 | command2 | command3 ...
_)でコマンドがサブシェルで実行されることです。変数は、サブシェル間、またはサブシェルとメインシェル間で共有されません。 whileループのring
は、メインシェルのring
とは異なります。
これを克服する1つの方法は、プロセス置換を使用することです。
_while read line; do ring+=("$line"); echo ${ring[-1]}; done < <(ls -las|tail -n +4)
_
<(command)
構文はプロセス置換と呼ばれ、コマンドの出力を名前付きパイプにリダイレクトします。次に、ファイルと同じように、おなじみの_<
_でリダイレクトされます。 _<
_を使用すると、サブシェルがないため、ring
変数が設定されます。
ファイルの行から配列を埋めるShell組み込みコマンドがあることに注意してください。
_mapfile -t ring < <(ls -las | tail -n +4)
_
これはうまくいくはずです:
ring=()
while read line
do
ring+=("$line")
echo ${ring[-1]}
done < <(ls -las | tail -n +4)
その理由は、whileループがパイプされるという事実により、サブシェルで実行されるためです。サブシェルは親シェル環境のコピーを使用し、サブシェルが終了するときにそれを返しません。
bashの場合は、コマンドグループ化の回避策を使用できます。中括弧が追加されていることに注意してください
ls -las | tail -n +4 | { while read line; do ring+=("$line"); echo ${ring[-1]}; done; echo ${ring[0]}; }