据我所知,进程替换(...)创建了fd
并将命令的输出存储在生成的fd中的括号中。
因此,这两个命令是等效的
$ ls -al
$ cat <(ls -al)
这里,我的问题是,生成的文件描述符保留多长时间?
我已经读过article,但似乎我的理解是错误的。
[如果将进程替换扩展为函数的参数,在调用函数期间扩展为环境变量,或者扩展为函数内的任何赋值,则进程替换将“保持打开”状态,以供内部的任何命令使用函数或其被调用者,直到返回设置该函数的函数为止。如果在被调用方中再次设置了相同的变量,除非新变量是本地变量,否则先前的进程替换将关闭,并且当被调用方返回时,调用方将无法使用它。
本质上,扩展到函数内变量的进程替换保持打开状态,直到发生进程替换的函数返回为止-即使将其分配给由函数调用者设置的局部变量也是如此。动态范围不能防止它们关闭。
阅读后,我的最佳猜测是所创建的fd在使用前不会关闭。
由此,我编写了一个非常愚蠢的代码,如下所示
#!/bin/bash
test_subs () {
echo "Inside a function"
FD2=<(ls -al)
cat $FD1
cat $FD2
}
FD1=<(ls -al)
test_subs
Result======================================
Inside a function
cat: /dev/fd/63: No such file or directory
cat: /dev/fd/63: No such file or directory
似乎新打开的fd在命令运行后立即关闭。
生成的fd会保留多长时间,然后替换进程的范围是什么?
似乎没有文档,因此不能保证过程替代<(...)
的范围。根据我的实验,如果满足以下所有条件,则可以进行过程替换a=<(...)
:
a
在范围内。<(...)
创建的命名管道尚未关闭或尚未完全读取。a=<(...)
和访问$a
将在同一提示符下。也就是说,在键入命令期间,bash将<< not >>提示。[在许多情况下,按Enter不会引起提示,例如在子外壳(...)
,上下文{...}
或诸如while
,for
和if
之类的块语句中。 在创建<(...)
和使用$a
之间,bash内置程序read
,mapfile
和readarray
。在某些情况下,您可以包装这些读物。但是,我不知道为什么在$(...)
无效的情况下使用(...)
进行包装是有效的。✱如果您在函数之外,请完全按照脚本中的说明键入它们。单行a=<(...); cat "$a"
与两行a=<(...)
和cat "$a"
之间有所不同。如果在函数内部,请用Enter
替换所有未引用的;
。长篇故事(...)
和上下文{...}
。除了链接的Bash Hackers Wiki中的错误注释外,我找不到任何相关文档。甚至bash's manual都没有提及进程替换的范围。因此,我们只能进行实验(或阅读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}'
这是我系统的输出(美化)(WSL 1中Debian 10 Buster上的bash 5.0.3)。
,-- in scope? V no define, use yes define and use in same line yes define and use in subshell yes define and use in context yes define and use in && chain yes define in context and use in || chain yes define and use in for loop body yes define and use in while loop head yes define and use in same case yes define in case, use in fall-through no define and use inside function in same line no define local and use inside function in same line no define, use as function argument yes define, use as function argument in same line yes on-the-fly export, use in different shell no export, use in different shell no define in command substitution, use in parent in same line no read from here-string, use in parent in same line no read from process substitution, use in parent in same line no read from pipe and use in same line yes define, unrelated read from file, use in same line no define, unrelated read from process substitution, use in same line yes define, unrelated cat from process substitution, use in same line no define, unrelated read ... in subshell, use in same line yes define, unrelated read ... in command substitution, use in same line
对于我对这些结果的解释,请参阅本答案开头的TL; DR。