当我们重定向 shell 脚本的输出时,我注意到一些相当奇怪的行为,该脚本本身将其一些输出重定向到 /dev/stdout 或 /dev/stderr。
外壳脚本
$ cat test.sh
#!/bin/bash -x
echo stdout
echo stderr >&2
echo '/dev/stdout' > /dev/stdout
echo '/dev/stderr' > /dev/stderr
基线:无重定向
$ ./test.sh
+ echo stdout
stdout
+ echo stderr
stderr
+ echo /dev/stdout
/dev/stdout
+ echo /dev/stderr
/dev/stderr
如果我们不执行任何重定向,一切都会按我们的预期显示。
重定向标准输出
$ ./test.sh > out
+ echo stdout
+ echo stderr
stderr
+ echo /dev/stdout
+ echo /dev/stderr
/dev/stderr
$ cat out
/dev/stdout
当我们重定向 stdout 时,“/dev/stdout”行会按预期重定向,但“stdout”行不再出现在任何地方。
将流重定向到单独的文件
$ ./test.sh > out 2> err
$ cat out
/dev/stdout
$ cat err
/dev/stderr
不仅“stderr”,而且“bash -x”行也消失了。
将流重定向到同一文件
$ ./test.sh > out 2>&1
$ cat out
/dev/stderr
在最后一种情况下,我们丢失了上一个示例中的所有内容,并且之前成功重定向到该文件的“/dev/stdout”也丢失了。
在 shell 脚本中使用 exec 行进行重定向,例如exec 1>out; exec 2>&1;
,产生与从命令行重定向相同的行为。
问题:为什么缺少的行会丢失,脚本的每一行会发生什么(包括通过命令行重定向执行的隐式执行行)从而导致这种情况发生?优选地,后者的答案将描述所涉及的系统调用(dup2?)。
答案1
因为您正在重定向到文件
echo '/dev/stdout' > /dev/stdout
echo '/dev/stderr' > /dev/stderr
将覆盖(而不是附加到)文件。当您不重定向时,您不会注意到这一点,因为您只能附加到 stdout/stderr。
用。。。来代替
echo '/dev/stdout' >> /dev/stdout
echo '/dev/stderr' >> /dev/stderr
一切都恢复正常了。