gpt4 book ai didi

Bash:进程替换的范围是什么?

转载 作者:行者123 更新时间:2023-12-03 16:14:56 26 4
gpt4 key购买 nike

据我所知,进程替换 <(...)/>(...) 创建了 fd

并将括号中的命令输出存储到生成的 fd 中。

因此,这两个命令是等价的

$ ls -al
$ cat <(ls -al)

在这里,我的问题是,生成的文件描述符保留多长时间?

我读过这个 article ,但似乎我的理解是错误的。

If a process substitution is expanded as an argument to a function, expanded to an environment variable during calling of a function, or expanded to any assignment within a function, the process substitution will be "held open" for use by any command within the function or its callees, until the function in which it was set returns. If the same variable is set again within a callee, unless the new variable is local, the previous process substitution is closed and will be unavailable to the caller when the callee returns.

In essence, process substitutions expanded to variables within functions remain open until the function in which the process substitution occured returns - even when assigned to locals that were set by a function's caller. Dynamic scope doesn't protect them from closing.



我最好的猜测是,在阅读之后,创建的 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维持多久,那么进程替换的范围是什么?

最佳答案

TL; 博士

似乎没有文档,因此无法保证进程替换的范围 <(...) .我认为保持进程替换在范围内的唯一安全方法是将它们直接定义为参数 cmd <(...) , 即时导出的变量 VAR=<(...) cmd ,或重定向 cmd < <(...) .以这种方式定义的进程替换仍在范围内,而 cmd在跑。

长篇大论

我像你一样解释了 Bash Hackers Wiki 中引用的文章。同样,我得出了同样的结论,即在函数内声明用于进程替换的变量并不能保证它们保持打开状态。在某些系统上,还有许多其他方法可以使它们保持打开状态,尤其是使用 command groups像子 shell (...)和上下文 {...} .但是,这些技巧在某些系统上仍然失败。

除了链接的 Bash Hackers Wiki 中的错误评论外,我找不到任何相关文档。偶bash's manual不谈进程替换的范围。所以我们坚持实验(或阅读 bash 的源代码,我没有)。

以下脚本创建了一些场景来检查何时进程替换 <(...)仍在范围内。请注意,存在非常细微的差异。例如:使用 ; 在同一行中编写两个命令会有所不同。或每个命令在其自己的行中。当然,这份 list 并不完整。随意扩展它。

#! /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。

关于Bash:进程替换的范围是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46660020/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com