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
$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)-release (x86_64-apple-darwin15) 版權所有 (C) 2007 Free Software Foundation, Inc.
awk '!x[$0]++' <<< "$list" | **同時讀取 -r 行;做** *數組***[count++]=$line 完畢**
在這種情況下,
array
(斜體)是**subshell
**(粗體)的一部分。可以說,當子外殼還活著時,
$line
and$array
就具有價值。一旦 subshell 完成,也就是死亡,父(生成器)環境就會恢復。這包括刪除子shell 中設置的任何變數。
在這種情況下:
$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] { }
或者按照說明書。
我們可以從管道開始
$$ … $$管道中的每個命令都在其自己的子 shell中執行(請參閱命令執行環境)。$$ … $$
命令執行環境將冒險擴展如下:
$$ … $$在這個單獨的環境 中呼叫的命令不會影響 shell 的執行環境。 命令替換、用括號分組的命令和非同步命令在作為 shell 環境副本的子 shell 環境中呼叫,除了 shell 擷取的陷阱被重置為 shell 在呼叫時從其父 shell 繼承的值。作為管道的一部分呼叫的內置命令也在子 shell 環境中執行。對子 shell 環境所做的更改不會影響 shell 的執行環境。
$$ … $$
它不能影響:因此它不能設置。
但是,我們可以重定向並朝以下方向做一些事情:
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