带重定向的 bash 命令替换:错误的文件描述符

带重定向的 bash 命令替换:错误的文件描述符

以下命令在 dash 中有效,但在 bash 中失败,并显示“错误文件描述符”。

$ dash -c 'out=$(echo "to fd3" >&3; echo "to stdout") 3>&1; echo "out: $out"'
to fd3
out: to stdout

$ bash -c 'out=$(echo "to fd3" >&3; echo "to stdout") 3>&1; echo "out: $out"'
bash: 3: Bad file descriptor
out: to stdout

当我用子 shell 替换命令替换时,它似乎可以在 dash 和 bash 中工作。

$ dash -c '(echo "to fd3" >&3; echo "to stdout") 3>&1'
to fd3
to stdout

$ bash -c '(echo "to fd3" >&3; echo "to stdout") 3>&1'
to fd3
to stdout

版本:

$ bash --version
GNU bash, version 4.4.12(1)-release (x86_64-unknown-linux-gnu)

不知道如何获得破折号版本。我系统上的手册页日期为 2003 年 1 月 19 日。


研究:

我查了一下 bash 和 dash 是如何执行命令的。这就是我发现的。

对于bash:https://www.gnu.org/software/bash/manual/bashref.html#Shell-Operation

对于破折号:http://man7.org/linux/man-pages/man1/dash.1.html(“简单命令”部分)

据我了解,两者都在重定向之前进行扩展。命令替换是一种扩展。因此,在命令替换中未设置文件描述符 3 是有道理的。

为什么它在破折号中起作用?为什么它在 bash 中不起作用?这是破折号的错误吗?还是bash?它到底是一个有效的构造吗?

答案1

重定向是在赋值扩展之前还是之后执行当没有命令时 POSIX 未指定,因此两者都是有效的,您都不能依赖其中任何一个。因此,为了便于携带,您需要:

{ out=$(echo "to fd3" >&3; echo "to stdout"); } 3>&1

AT&Tksh和 Bourne shell 的行为类似于bashzsh, pdksh,yash的行为dash与本例类似。

相关内容