我正在编写一个bash函数来获取所有git存储库,但是当我想将所有git存储库路径名存储到数组patharray
时,我遇到了一个问题。这是代码:
gitrepo() {
local opt
declare -a patharray
locate -b '\.git' | \
while read pathname
do
pathname="$(dirname ${pathname})"
if [[ "${pathname}" != *.* ]]; then
# Note: how to add an element to an existing Bash Array
patharray=("${patharray[@]}" '\n' "${pathname}")
# echo -e ${patharray[@]}
fi
done
echo -e ${patharray[@]}
}
我想将所有存储库路径保存到patharray
数组,但我无法在pipeline
和locate
之外的while
之外获取它命令
但是我可以在pipeline
命令中获取数组,如果没有注释,注释命令# echo -e ${patharray[@]}
运行良好,那么我该如何解决这个问题呢?
我尝试了export
命令,但它似乎无法将patharray
传递给管道。
答案 0 :(得分:4)
Bash在单独的SubShell中运行管道的所有命令。当包含while
循环的子shell结束时,您对patharray
变量所做的所有更改都将丢失。
您可以简单地将while
循环和echo
语句组合在一起,以便它们都包含在同一个子shell中:
gitrepo() {
local pathname dir
local -a patharray
locate -b '\.git' | { # the grouping begins here
while read pathname; do
pathname=$(dirname "$pathname")
if [[ "$pathname" != *.* ]]; then
patharray+=( "$pathname" ) # add the element to the array
fi
done
printf "%s\n" "${patharray[@]}" # all those quotes are needed
} # the grouping ends here
}
或者,您可以将代码结构化为不需要管道:使用ProcessSubstitution
(有关详细信息,请参阅Bash手册 - man bash | less +/Process\ Substitution
):
gitrepo() {
local pathname dir
local -a patharray
while read pathname; do
pathname=$(dirname "$pathname")
if [[ "$pathname" != *.* ]]; then
patharray+=( "$pathname" ) # add the element to the array
fi
done < <(locate -b '\.git')
printf "%s\n" "${patharray[@]}" # all those quotes are needed
}
答案 1 :(得分:2)
首先,使用array[${#array[*]}]="value"
或array+=("value1" "value2" "etc")
可以更好地附加到数组变量,除非您希望转换整个数组(不需要)。
现在,从pipeline commands are run in subprocesses开始,对管道命令中的变量所做的更改不会传播到它之外。有几种方法可以解决这个问题(大多数都列在Greg's BashFAQ/024中):
通过stdout传递结果
使用\0
作为分隔符,可以可靠地处理路径中的任何特殊字符(请参阅Capturing output of find . -print0 into a bash array阅读\0
- 分隔列表)
locate -b0 '\.git' | while read -r -d '' pathname; do dirname -z "$pathname"; done
或只是
locate -b0 '\.git' | xargs -0 dirname -z
避免在子流程中运行循环
完全避免管道
进程替换(一种特殊的,语法支持的FIFO情况,不需要手动清理;代码改编自Greg's BashFAQ/020):
i=0 #`unset i` will error on `i' usage if the `nounset` option is set
while IFS= read -r -d $'\0' file; do
patharray[i++]="$(dirname "$file")" # or however you want to process each file
done < <(locate -b0 '\.git')
使用lastpipe
选项(Bash 4.2中的新增功能) - 不运行子流程中管道的 last 命令(中等:具有全局效果)