vik*_*mun 2 bash git shell-script
我正在尝试获取目录中文件的所有未暂存修改的 bash 数组(使用 Git)。以下代码用于打印出目录中所有修改过的文件:
git -C $dir/.. status --porcelain | grep "^.\w" | cut -c 4-
Run Code Online (Sandbox Code Playgroud)
这打印
"Directory Name/File B.txt"
"File A.txt"
Run Code Online (Sandbox Code Playgroud)
我尝试使用
arr1=($(git status --porcelain | grep "^.\w" | cut -c 4-))
Run Code Online (Sandbox Code Playgroud)
但是之后
for a in "${arr1[@]}"; do echo "$a"; done
Run Code Online (Sandbox Code Playgroud)
(${arr1[@]}
印刷品周围有和没有引号
"Directory
Name/File
B.txt"
"File
A.txt"
Run Code Online (Sandbox Code Playgroud)
我也试过
git -C $dir/.. status --porcelain | grep "^.\w" | cut -c 4- | readarray arr2
Run Code Online (Sandbox Code Playgroud)
但是之后
for a in "${arr2[@]}"; do echo "$a"; done
Run Code Online (Sandbox Code Playgroud)
(带和不带引号${arr2[@]}
)不打印任何内容。declare -a arr2
预先使用也绝对没有任何作用。
我的问题是:如何将这些值读入数组?(这被用于我的 argos 插件gitbar,以防万一,所以你可以看到我的所有代码)。
ImH*_*ere 11
在 bash 中:
readarray -t arr2 < <(git … )
printf '%s\n' "${arr2[@]}"
Run Code Online (Sandbox Code Playgroud)
你的问题有两个不同的问题
壳分裂。
当你这样做时:
arr1=($(git … ))
Run Code Online (Sandbox Code Playgroud)
“命令扩展”未加引号,因此:它受制于 shell 拆分和 glob。
确切地看那个shell分裂做了什么,使用printf:
$ printf '<%s> ' $(echo word '"one simple sentence"')
<word> <"one> <simple> <sentence">
Run Code Online (Sandbox Code Playgroud)
通过引用可以避免这种情况:
$ printf '<%s> ' "$(echo word '"one simple sentence"')"
<word "one simple sentence">
Run Code Online (Sandbox Code Playgroud)
但这也可以避免在您想要的换行符上进行拆分。
管道
执行时:
git … | … | … | readarray arr2
Run Code Online (Sandbox Code Playgroud)
数组变量已arr2
设置,但在管道 ( |
) 关闭时它消失了。
如果您留在最后一个子shell中,则可以使用该值:
$ printf '%s\n' "First value." "Second value." |
{ readarray -t arr2; printf '%s\n' "${arr2[@]}"; }
First value.
Second value.
Run Code Online (Sandbox Code Playgroud)
但是值arr2
不会从管道中存活下来。
您需要使用 read 在换行符上拆分,而不是使用管道拆分。
从旧到新:
环形。
对于没有数组的旧壳(使用位置参数,唯一的准数组):
set --
while IFS='' read -r value; do
set -- "$@" "$value"
done <<-EOT
$(printf '%s\n' "First value." "Second value.")
EOT
printf '%s\n' "$@"
Run Code Online (Sandbox Code Playgroud)
设置数组(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[@]}"
Run Code Online (Sandbox Code Playgroud)Here-string我们可以使用 here-string ( )
代替 here document <<
( <<<
):
i=0; arr1=()
while IFS='' read -r value; do
arr1+=("$value")
done <<<"$(printf '%s\n' "First value." "Second value.")"
printf '%s\n' "${arr1[@]}"
Run Code Online (Sandbox Code Playgroud)进程替换
在支持它的 shell (ksh, zsh, bash) 中,您可以<( … )
用来替换 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[@]}"
Run Code Online (Sandbox Code Playgroud)
不同之处:<( )
能够发出 NUL 字节,而 here-string 可能会删除(或发出警告)NUL。默认情况下,here-string 添加尾随换行符。可能还有其他人AFAIK。
readarray
使用readarray
在bash
〔A〕(又名mapfile
)避免循环:
readarray -t arr2 < <(printf '%s\n' "First value." "Second value.")
printf '%s\n' "${arr2[@]}"
Run Code Online (Sandbox Code Playgroud)[a]在 ksh 中,您需要使用read -A
,它会在使用前清除变量,但需要一些“魔法”来拆分换行符并立即读取整个输入。
IFS=$'\n' read -d '' -A arr2 < <(printf '%s\n' "First value." "Second value.")
Run Code Online (Sandbox Code Playgroud)
您需要在 zsh 中加载一个mapfile
模块来执行类似的操作。