以下命令在 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 的行为类似于bash
;zsh
, pdksh
,yash
的行为dash
与本例类似。