BASH:awkを使用して一意の行をフィルタリングすると、長さ0の配列になります。

BASH:awkを使用して一意の行をフィルタリングすると、長さ0の配列になります。

注: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

しかし、$listawkでフィルタリングします。

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

おすすめ記事