使用 bash 將行讀入數組,每行一個元素
我正在嘗試獲取目錄中所有未暫存文件修改的 bash 數組(使用 Git)。以下程式碼用於列印目錄中所有修改過的文件:
git -C $dir/.. status --porcelain | grep "^.\w" | cut -c 4-
這列印
"Directory Name/File B.txt" "File A.txt"
我嘗試使用
arr1=($(git status --porcelain | grep "^.\w" | cut -c 4-))
但是之後
for a in "${arr1[@]}"; do echo "$a"; done
${arr1[@]}
(無論是否有印刷品周圍的引號"Directory Name/File B.txt" "File A.txt"
我也試過
git -C $dir/.. status --porcelain | grep "^.\w" | cut -c 4- | readarray arr2
但是之後
for a in "${arr2[@]}"; do echo "$a"; done
(無論是否帶有引號
${arr2[@]}
)都不會列印任何內容。事先使用declare -a arr2
也絕對沒有任何作用。我的問題是:如何將這些值讀入數組?(這被用於我的 argos 外掛gitbar,以防萬一,所以你可以看到我所有的程式碼)。
TL;博士
在 bash 中:
readarray -t arr2 < <(git … ) printf '%s\n' "${arr2[@]}"
你的問題有兩個不同的問題
- 殼裂。
當你這樣做時:
arr1=($(git … ))
“命令擴展”未加引號,因此:它受外殼拆分和 glob 的影響。
確切地看到 shell 拆分的作用,使用 printf:
$ printf '<%s> ' $(echo word '"one simple sentence"') <word> <"one> <simple> <sentence">
這可以通過引用來避免:
$ printf '<%s> ' "$(echo word '"one simple sentence"')" <word "one simple sentence">
但這也可以避免您想要的換行符拆分。 2. 管道
執行時:
git … | … | … | readarray arr2
數組變數
arr2
已設置,但在管道 (|
) 關閉時它消失了。如果您留在最後一個子外殼內,則可以使用該值:
$ printf '%s\n' "First value." "Second value." | { readarray -t arr2; printf '%s\n' "${arr2[@]}"; } First value. Second value.
但價值
arr2
不會從管道中存活下來。解決方案
您需要使用 read 來分割換行符,但不需要使用管道。
從舊到新:
- 環形。
對於沒有數組的舊 shell(使用位置參數,唯一的準數組):
set -- while IFS='' read -r value; do set -- "$@" "$value" done <<-EOT $(printf '%s\n' "First value." "Second value.") EOT printf '%s\n' "$@"
設置數組(ksh、zsh、bash)
i=0; arr1=() while IFS='' read -r value; do arr1+=("$value") done <<-EOT $(printf '%s\n' "First value." "Second value.") EOT printf '%s\n' "${arr1[@]}"
- Here-string我們可以使用 here-string ( )
代替此處的文件 ( ):
<<``<<<
i=0; arr1=() while IFS='' read -r value; do arr1+=("$value") done <<<"$(printf '%s\n' "First value." "Second value.")" printf '%s\n' "${arr1[@]}"
- 程序替換
在支持它的 shell(ksh、zsh、bash)中,您可以使用
<( … )
替換此處的字元串:i=0; arr1=() while IFS='' read -r value; do arr1+=("$value") done < <(printf '%s\n' "First value." "Second value.") printf '%s\n' "${arr1[@]}"
不同之處在於:
<( )
能夠發出 NUL 字節,而 here-string 可能會刪除(或發出警告)NUL。預設情況下,here-string 添加尾隨換行符。可能還有其他人AFAIK。 4. readarray中使用
readarray``bash
$$ a $$(又名mapfile
)以避免循環:readarray -t arr2 < <(printf '%s\n' "First value." "Second value.") printf '%s\n' "${arr2[@]}"
**$$ a $$**在 ksh 中,您將需要使用
read -A
,它在使用前清除變數,但需要一些“魔法”來分割換行符並一次讀取整個輸入。IFS=$'\n' read -d '' -A arr2 < <(printf '%s\n' "First value." "Second value.")
你需要在 zsh中載入一個
mapfile
模組來做類似的事情。