我有一个 bash 脚本(见这里)我用来按文件名对子目录中的文件列表进行排序。
该脚本将排序后的文件附加到hooks/pre-relevant/
,然后是文件命名的 hooks/pre-relevant
,然后是名为 的文件hooks/relevant
,然后hooks/relevant/
使用append_hook
以下函数对 中的文件进行排序:
hooks=()
# Run a hook script, if it's executable, with the input from this invocation
append_hook () {
if [[ -f "$1" && -x "$1" ]]; then
hooks+=("$1")
fi
}
我正在使用以下目录结构对其进行测试:
testing-range/plugins/
|-- bar
| `-- hooks
| |-- irrelevant
| |-- only-one
| `-- relevant
|-- dickory
| `-- hooks
| `-- pre-relevant
|-- doc
| `-- hooks
| |-- perl-envsubst
| `-- relevant
| |-- 00
| `-- 20
|
|-- factory
| `-- hooks
| `-- relevant
`-- hickory
`-- hooks
|-- pre-relevant
| `-- 30
`-- relevant
`-- 10
当我使用这个多步数组代码附加文件时:
append_numbered_hooks () {
# Gather every file into an array, prefixing each item with the
# filename of the script (its position in sort order)
local filelist=()
for hook in "$PLUSHU_ROOT"/plugins/*/hooks/"$hookname"/*; do
filelist+=("${hook##*/}/$hook")
done
# Sort the array numerically
printf '%s\0' "${filelist[@]}" | sort -nz | IFS= read -rd '' -a filelist
# Append each script in sorted order
for hookline in "${filelist[@]}"; do
append_hook "${hookline#*/}"
done
}
我明白了几乎正确的输出:
hickory/hooks/pre-relevant/30
dickory/hooks/pre-relevant
bar/hooks/relevant
factory/hooks/relevant
doc/hooks/relevant/00
doc/hooks/relevant/20
hickory/hooks/relevant/10
然而,当我使用这个更简单的管道附加文件时:
append_numbered_hooks () {
for hook in "$PLUSHU_ROOT"/plugins/*/hooks/"$1"/*; do
printf '%s\0' "${hook##*/}/$hook"
done | sort -nz | while IFS= read -rd '' hookline; do
append_hook "${hookline#*/}"
done
}
编号的文件不会出现在 for "${hooks[@]}" 循环中:
dickory/hooks/pre-relevant
bar/hooks/relevant
factory/hooks/relevant
这是怎么回事?正确的值应该是:
hickory/hooks/pre-relevant/30
dickory/hooks/pre-relevant
bar/hooks/relevant
factory/hooks/relevant
doc/hooks/relevant/00
hickory/hooks/relevant/10
doc/hooks/relevant/20
答案1
从http://www.gnu.org/software/bash/manual/bashref.html#Pipelines
管道中的每个命令都在其自己的子 shell 中执行
因此,您正在更改子 shell 中的变量。当子 shell 退出时,这些更改就会消失。
你可能会发现流程替代有帮助。
append_numbered_hooks () {
while IFS= read -rd '' hookline; do
append_hook "${hookline#*/}"
done < <(
for hook in "$PLUSHU_ROOT"/plugins/*/hooks/"$1"/*; do
printf '%s\0' "${hook##*/}/$hook"
done |
sort -nz
)
}