为什么这些值在附加到管道时没有正确附加?

Stu*_*ley 1 bash pipe

我有一个 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
}
Run Code Online (Sandbox Code Playgroud)

我正在用这个目录结构测试它:

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
Run Code Online (Sandbox Code Playgroud)

当我使用这个多步数组代码附加文件时:

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
}
Run Code Online (Sandbox Code Playgroud)

我得到几乎正确的输出:

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
Run Code Online (Sandbox Code Playgroud)

然而,当我使用这个更简单的管道附加文件时:

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
}
Run Code Online (Sandbox Code Playgroud)

编号文件不会出现在 for "${hooks[@]}" 循环中:

dickory/hooks/pre-relevant
bar/hooks/relevant
factory/hooks/relevant
Run Code Online (Sandbox Code Playgroud)

这是怎么回事?正确的值应该是:

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
Run Code Online (Sandbox Code Playgroud)

gle*_*man 6

来自http://www.gnu.org/software/bash/manual/bashref.html#Pipelines

管道中的每个命令都在其自己的子 shell 中执行

因此,您正在更改子shell 中的变量。当 subshel​​l 退出时,这些更改就会消失。

您可能会发现过程替换很有帮助。

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
  )
}
Run Code Online (Sandbox Code Playgroud)