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

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

我有一个 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
  )
}

相关内容