7

これをkshで機能させることはできますが、bashでは機能させられないため、本当に気が狂います。うまくいけば、私が見落としていることは明らかです。

出力の各行が配列インデックスに格納される外部コマンドを実行する必要があります。

この単純化された例は、ループ内で配列を正しく設定しているように見えますが、ループが完了すると、それらの配列の割り当てはなくなりますか? まるでループが完全に外部シェルとして扱われているかのようです。

ジャンク.txt

this is a
test to see
if this works ok

testa.sh

#!/bin/bash

declare -i i=0
declare -a array

echo "Simple Test:"
array[0]="hello"
echo "array[0] = ${array[0]}"

echo -e "\nLoop through junk.txt:"
cat junk.txt | while read line
do
    array[i]="$line"
    echo "array[$i] = ${array[i]}"
    let i++
done

echo -e "\nResults:"
echo "       array[0] = ${array[0]}"
echo " Total in array = ${#array[*]}"
echo "The whole array:"
echo ${array[@]}

出力

Simple Test:
array[0] = hello

Loop through junk.txt:
array[0] = this is a
array[1] = test to see
array[2] = if this works ok

Results:
      array[0] = hello
Total in array = 1
The whole array:
hello

そのため、ループ内で array[i] を割り当て、echo がそれを検証します。しかし、ループの後、「hello」を含む array[0] に戻り、他の要素はありません。

bash 3、4、および異なるプラットフォームで同じ結果。

4

1 に答える 1

9

while ループはパイプライン内にあるため、ループ本体のすべての変数の割り当ては、ループが実行されるサブシェルに対してローカルです。(kshサブシェルでコマンドを実行しないと思います。そのため、で問題が発生しbashます。)代わりに次のようにします。

while read line
do
    array[i]="$line"
    echo "array[$i] = ${array[i]}"
    let i++
done < junk.txt

まれに、単一のファイルを別のコマンドcatにパイプするために使用したい場合があります。代わりに入力リダイレクトを使用してください。

更新:ファイルではなくコマンドから実行する必要があるため、別のオプション(利用可能な場合)はプロセス置換です:

while read line; do
...
done < <( command args ... )

プロセス置換が利用できない場合は、一時ファイルに出力し、そのファイルから入力をリダイレクトする必要があります。

bash 4.2 以降を使用している場合は、ループの前にこれら 2 つのコマンドを実行できます。while ループはパイプラインの最後のコマンドであるため、元のパイプインツーザループが機能します。

set +m    # Turn off job control; it's probably already off in a non-interactive script
shopt -s lastpipe
cat junk.txt | while read line; do ...; done

更新 2: これは、user1596414 のコメントに基づくループのないソリューションです。

array[0]=hello
IFS=$'\n' array+=( $(command) )

コマンドの出力は、改行のみに基づいて単語に分割され (各行が個別の単語になるように)、結果のスロットごとの行配列を元の配列に追加します。配列を構築するためにループのみを使用している場合、これは非常に便利です。Python のリスト内包表記に漠然と似た、少量の行ごとの処理に対応するように変更することもできます。

于 2012-08-13T21:02:48.897 に答える