Bash

使用 bash 將行讀入數組,每行一個元素

  • December 6, 2020

我正在嘗試獲取目錄中所有未暫存文件修改的 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[@]}"

你的問題有兩個不同的問題

  1. 殼裂。

當你這樣做時:

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 來分割換行符,但不需要使用管道。

從舊到新:

  1. 環形。

對於沒有數組的舊 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[@]}"
  1. 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[@]}"
  1. 程序替換

在支持它的 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模組來做類似的事情。

引用自:https://unix.stackexchange.com/questions/485221