
注:Jeff SchallerとSteeldriverに感謝します。しかし、どちらも回答として公開されていないため、解決済みとしてマークする方法がわかりません。これでパイプ/サブシェルについてよりよく理解するようになりました。私はこれを一度知っていたと確信していますが、bashで複雑なものを試したのは長い時間がかかりました。
両方ともawkのフィルタリングされた結果を変数に割り当てます。プロセスの交換私のために動作します。ソートされていない一意の行を読み取る最終コードは次のとおりですstdin
。
while read -r FILE
do
...
done < <(awk '!x[$0]++')
もっと読むプロセスの交換この質問を見つけ、同様の問題に対する解決策を探している人のためです。
元の質問:
サイトを検索しましたが、私の質問に対する回答が見つかりませんでした。
標準入力から配列を作成しており、一意の行をフィルタリングする必要があります。そのために、私が読んだawk '!x[$0]++'
略語を使用しています。
awk 'BEGIN { while (getline s) { if (!seen[s]) print s; seen[s]=1 } }'
。
フィルタは期待どおりに機能しますが、問題はループで生成された配列が空でwhile read
あることです。
$list
たとえば(代わりに使用されますstdin
):
list=$'red apple\nyellow banana\npurple grape\norange orange\nyellow banana'
while read -r line; do
array[count++]=$line
done <<< "$list"
echo "array length = ${#array[@]}"
counter=0
while [ $counter -lt ${#array[@]} ]; do
echo ${array[counter++]}
done
生産する:
array length = 5
red apple
yellow banana
purple grape
orange orange
yellow banana
しかし、$list
awkでフィルタリングします。
list=$'red apple\nyellow banana\npurple grape\norange orange\nyellow banana'
awk '!x[$0]++' <<< "$list" | while read -r line; do
array[count++]=$line
done
echo "array length = ${#array[@]}"
counter=0
while [ $counter -lt ${#array[@]} ]; do
echo ${array[counter++]}
done
生産する:
array length = 0
しかし、出力はawk '!x[$0]++' <<< "$list"
大丈夫に見えます。
red apple
yellow banana
purple grape
orange orange
while read
ループの各行を確認してみました。
list=$'red apple\nyellow banana\npurple grape\norange orange\nyellow banana'
i=0
awk '!x[$0]++' <<< "$list" | while read -r line; do
echo "line[$i] = $line"
let i=i+1
done
よさそうだ:
line[0] = red apple
line[1] = yellow banana
line[2] = purple grape
line[3] = orange orange
私がここで何を見逃しているのでしょうか?
重要な場合は、bash 3.2.57を使用しています。
GNU bash, バージョン 3.2.57(1)-リリース(x86_64-apple-darwin15) Copyright (C) 2007 Free Software Foundation, Inc.
答え1
awk '!x[$0]++' <<< "$list" |また、-r 行を読みます。 大量に[カウント++] = $行 完璧
これarray
(イタリック体) この場合は次の一部です。subshell
(勇敢な)。
そして価値が$line
あります$array
同時にジケが生きていると言えます。
サブシェルが完了すると(つまり、終了すると)、親(ジェネレータ)環境が復元されます。これには、サブシェルに設定されているすべての変数の削除が含まれます。
この場合:
削除、$array
削除されました。$line
この試み:
list=$'red apple\nyellow banana\npurple grape\norange orange\nyellow banana'
awk '!x[$0]++' <<< "$list" | while read -r line; do
array[count++]=$line
printf "array[%d] { %s\n" ${#array[@]} # array[num_of_elements] {
printf " %s\n" "${array[@]}" # elements
printf "}\n" # } end of array
done
printf "\n[ %s ]\n\n" "END OF SUBSHELL (PIPE)"
printf "array[%d] {\n" ${#array[@]}
printf " %s\n" "${array[@]}"
printf "}\n"
生産する:
array[1] {
red apple
}
array[2] {
red apple
yellow banana
}
array[3] {
red apple
yellow banana
purple grape
}
array[4] {
red apple
yellow banana
purple grape
orange orange
}
[ END OF SUBSHELL (PIPE) ]
array[0] {
}
またはマニュアルに従います。
私たちは始めることができます管路
[...]パイプラインの各コマンドは独自に実行されます。サブシェル(望むよりコマンド実行環境)。 [… ]
しかもコマンド実行環境冒険は次のように拡張されます。
[...] ここで呼び出されるコマンドは独立した環境 できないシェルの実行環境に影響します。
コマンドの置換、括弧で囲まれたコマンド、および非同期コマンドは、シェル環境と重複するサブシェル環境で呼び出されます。ただし、シェルによって捕捉されたトラップは、シェルが親シェルから継承した値にリセットされます。祈り。パイプラインの一部として呼び出される組み込みコマンドは、サブシェル環境でも実行されます。サブシェル環境への変更は、シェルの実行環境には影響しません。[… ]
影響しないので設定できません。
ただし、次の方向にリダイレクトして操作を実行できます。
list=$'red apple\nyellow banana\npurple grape\norange orange\nyellow banana'
while read -r line; do
arr[count++]=$line
done <<<"$(awk '!x[$0]++' <<< "$list")"
echo "arr length = ${#arr[@]}"
count=0
while [[ $count -lt ${#arr[@]} ]]; do
echo ${arr[count++]}
done
答え2
問題に対するいくつかの解決策ループなし
# use bash's mapfile with process substitution
mapfile -t arr < <( awk '!x[$0]++' <<<"$list" )
# use array assignment syntax (at least bash, ksh, zsh)
# of a command-substituted value split at newline only
# and (if the data can contain globs) globbing disabled
set -f; IFS='\n' arr=( $( awk '!x[$0]++' <<<"$list" ) ); set +f