从管道命令追加到数组变量
Append to an array variable from a pipeline command
我正在编写一个 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
数组,但我无法在由 locate
和 [=15= 组成的 pipeline
之外获取它]命令。
但是我可以在 pipeline
命令中获取数组,注释命令 # echo -e ${patharray[@]}
如果不注释则可以正常工作,那么我该如何解决问题呢?
我试过 export
命令,但似乎无法将 patharray
传递给管道。
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
}
首先,附加到数组变量最好用 array[${#array[*]}]="value"
或 array+=("value1" "value2" "etc")
完成,除非你想转换整个数组(你不想)。
现在,自 , changes made to a variable inside a pipeline command will not propagate to outside it. There are a few options to get around this (most are listed in Greg's BashFAQ/024):
通过标准输出传递结果
- 最简单;无论如何,您都需要这样做才能从函数中获取值(尽管 there are ways to return a proper variable)
路径中的任何特殊字符都可以通过使用 [=15=]
作为分隔符来可靠地处理(请参阅 Capturing output of find . -print0 into a bash array 以阅读 [=15=]
分隔的列表)
locate -b0 '\.git' | while read -r -d '' pathname; do dirname -z "$pathname"; done
或者干脆
locate -b0 '\.git' | xargs -0 dirname -z
避免运行在子进程中循环
完全避免管道
- 临时 file/FIFO(不好:需要手动清理,其他人可以访问)
- 临时变量(一般:不必要的内存开销)
进程替换(一种特殊的、语法支持的 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 $'[=12=]' file; do
patharray[i++]="$(dirname "$file")" # or however you want to process each file
done < <(locate -b0 '\.git')
使用 lastpipe
选项(Bash 4.2 中的新选项)- 运行 last 命令不是子流程中的管道(一般:具有全局效果)
我正在编写一个 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
数组,但我无法在由 locate
和 [=15= 组成的 pipeline
之外获取它]命令。
但是我可以在 pipeline
命令中获取数组,注释命令 # echo -e ${patharray[@]}
如果不注释则可以正常工作,那么我该如何解决问题呢?
我试过 export
命令,但似乎无法将 patharray
传递给管道。
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
}
首先,附加到数组变量最好用 array[${#array[*]}]="value"
或 array+=("value1" "value2" "etc")
完成,除非你想转换整个数组(你不想)。
现在,自
通过标准输出传递结果
- 最简单;无论如何,您都需要这样做才能从函数中获取值(尽管 there are ways to return a proper variable)
路径中的任何特殊字符都可以通过使用
[=15=]
作为分隔符来可靠地处理(请参阅 Capturing output of find . -print0 into a bash array 以阅读[=15=]
分隔的列表)locate -b0 '\.git' | while read -r -d '' pathname; do dirname -z "$pathname"; done
或者干脆
locate -b0 '\.git' | xargs -0 dirname -z
避免运行在子进程中循环
完全避免管道
- 临时 file/FIFO(不好:需要手动清理,其他人可以访问)
- 临时变量(一般:不必要的内存开销)
进程替换(一种特殊的、语法支持的 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 $'[=12=]' file; do patharray[i++]="$(dirname "$file")" # or however you want to process each file done < <(locate -b0 '\.git')
使用
lastpipe
选项(Bash 4.2 中的新选项)- 运行 last 命令不是子流程中的管道(一般:具有全局效果)