TL;博士
似乎没有文档,因此无法保证流程替换的范围<(...)
。我认为将进程替换保持在范围内的唯一安全方法是将它们直接定义为参数cmd <(...)
、即时导出的变量VAR=<(...) cmd
或重定向cmd < <(...)
。以这种方式定义的进程替换在运行时仍然在范围内cmd
。
长篇大论
我像你一样解释了来自 Bash Hackers Wiki 的引用文章。同样,我得出了相同的结论,即在函数内声明进程替换的变量并不能保证它们保持打开状态。在某些系统上,还有许多其他方法可以让它们保持打开状态,尤其是使用命令组,如(...)
subshells 和 contextes {...}
。但是,这些技巧在某些系统上仍然失败。
除了链接的 Bash Hackers Wiki 中的错误评论外,我找不到任何相关文档。甚至bash 的手册也没有谈到进程替换的范围。所以我们被困在实验中(或阅读bash
我没有的源代码)。
以下脚本创建了一些场景来检查进程替换何时<(...)
保持在范围内。请注意,存在非常细微的差异。例如:使用在同一行中编写两个命令;
还是在自己的行中编写每个命令都会有所不同。当然,这份清单并不完整。随意扩展它。
#! /usr/bin/env bash
echo 'define, use'
a=<(echo ok);
cat "$a"; unset a
echo 'define and use in same line'
a=<(echo ok); cat "$a"; unset a
echo 'define and use in subshell'
(a=<(echo ok);
cat "$a")
echo 'define and use in context'
{ a=<(echo ok)
cat "$a"; }; unset a
echo 'define and use in && chain'
a=<(echo ok) &&
cat "$a"; unset a
echo 'define in context and use in || chain'
{ a=<(echo ok); false; } || cat "$a"; unset a
echo 'define and use in for loop body'
for i in 1; do
a=<(echo ok)
cat "$a"
done
echo 'define and use in while loop head'
while
a=<(echo ok)
cat "$a"
false
do true; done; unset a
echo 'define and use in same case'
case x in
x)
a=<(echo ok)
cat "$a"
;;
esac; unset a
echo 'define in case, use in fall-through'
case x in
x)
a=<(echo ok)
;&
y)
cat "$a"
;;
esac; unset a
echo 'define and use inside function in same line'
f() { a=<(echo ok); cat "$a"; }; f; unset a f
echo 'define local and use inside function in same line'
f() { local a=<(echo ok); cat "$a"; }; f; unset a f
echo 'define, use as function argument'
f() { cat "$1"; }; a=<(echo ok)
f "$a"; unset a f
echo 'define, use as function argument in same line'
f() { cat "$1"; }; a=<(echo ok); f "$a"; unset a f
echo 'on-the-fly export, use in different shell'
a=<(echo ok) dash -c 'cat "$a"'
echo 'export, use in different shell'
export a=<(echo ok)
dash -c 'cat "$a"'; unset a
echo 'define in command substitution, use in parent in same line'
a=$(echo <(echo ok)); cat "$a"; unset a
echo 'read from here-string, use in parent in same line'
read a <<< <(echo ok); cat "$a"; unset a
echo 'read from process substitution, use in parent in same line'
read a < <(echo <(echo ok)); cat $a; unset a
echo 'read from pipe and use in same line'
shopt -s lastpipe; # TODO add `set +m` when running interactively
echo <(echo ok) | read -r a; cat "$a"
shopt -u lastpipe; unset a
echo 'define, unrelated read from file, use in same line'
a=<(echo ok); read < /etc/passwd; cat "$a"; unset a
echo 'define, unrelated read from process substitution, use in same line'
a=<(echo ok); read < <(echo unused); cat "$a"; unset a
echo 'define, unrelated cat from process substitution, use in same line'
a=<(echo ok); cat <(echo unused) > /dev/null; cat "$a"; unset a
echo 'define, unrelated read ... in subshell, use in same line'
a=<(echo ok); (read < <(echo unused)); cat "$a"; unset a b
echo 'define, unrelated read ... in command substitution, use in same line'
a=<(echo ok); b=$(read < <(echo unused)); cat "$a"; unset a b
# output can be prettified using
# ./script 2> /dev/null |
# awk 'p!="ok"{if($0=="ok")print "yes " p;else print "no " p}{p=$0}'
这些是我的系统的(美化的)输出
In scope on bash 5.0.17 on Arch Linux (kernel 5.6.15-arch1-1)
| In scope on bash 5.0.3 on Debian 10 Buster inside WSL 1
| | In scope on bash 4.3.48 on Ubuntu 16.04.6 LTS
↓ ↓ ↓
no no no define, use
yes yes no define and use in same line
yes yes no define and use in subshell
yes yes no define and use in context
yes yes no define and use in && chain
yes yes no define in context and use in || chain
yes yes no define and use in for loop body
yes yes no define and use in while loop head
yes yes no define and use in same case
yes yes no define in case, use in fall-through
no no no define and use inside function in same line
no no no define local and use inside function in same line
no no no define, use as function argument
yes yes no define, use as function argument in same line
yes yes yes on-the-fly export, use in different shell
no no no export, use in different shell
no no no define in command substitution, use in parent in same line
no no no read from here-string, use in parent in same line
no no no read from process substitution, use in parent in same line
no no no read from pipe and use in same line
yes yes no define, unrelated read from file, use in same line
yes no no define, unrelated read from process substitution, use in same line
yes yes no define, unrelated cat from process substitution, use in same line
no no no define, unrelated read ... in subshell, use in same line
yes yes no define, unrelated read ... in command substitution, use in same line
对于我对这些结果的解释,请参阅此答案开头的 TL;DR。