bash重定向中出现意外行为

时间:2015-11-06 09:51:23

标签: bash

我在bash中使用重定向时发现了一种奇怪且完全出乎意料的行为,即使我设法解决它,我也想知道它为什么会发生。

如果我运行此命令:{ echo wtf > /dev/stdout ; } >> wtf.txt N次,我希望看到填充N“wtf”行。我在文件中找到的是一行。

我认为既然第一个命令是在截断模式下打开/ dev / stdout,那么模式会被第二个文件描述符(wtf.txt)继承,然后被完全擦除,但是我想知道是否你们中的一些人可能会更好地解释它,如果这是正确的行为或错误。

为了清楚起见,我使用的命令是另一个,但使用 echo 示例更容易理解它。原始命令是一个需要输出文件作为参数的命令,因为我想在stdout上输出,所以我将 / dev / stdout 作为参数传递。可以使用命令openssl rand -hex 4 -out /dev/stdout >> wtf.txt验证相同的行为。

最后,我设法解决了以下列方式将附加操作委托给 tee 的问题:{ echo wtf > /dev/stdout } | tee -a wtf.txt > /dev/null

1 个答案:

答案 0 :(得分:1)

您可以使用strace检查会发生什么:

strace -o wtf-trace.txt -ff bash -c '{ (echo wtf) > /dev/stdout; } >> wtf.txt'

在我的情况下,这将生成两个文件,例如wtf-trace.txt.12889wtf-trace.txt.12890。结果是,流程1 >> wtf.txt

open("wtf.txt", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3
dup2(3, 1)                              = 1
close(3)                                = 0
clone(child_stack=0, .................) = 12890
wait4(-1, [{WIFEXITED(s) .............) = 12890
exit_group(0)                           = ?

第一个进程打开或创建“wtf.txt”以便附加并获取FD 3.之后,它将FD 1与FD 3复制并关闭FD 3.此时它分叉(克隆),等待它退出并且退出。

第二个进程{ echo wtf > /dev/stdout }通过FD 1(stdout)继承文件,它确实:

open("/dev/stdout", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
dup2(3, 1)                              = 1
close(3)                                = 0
fstat(1, {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
write(1, "wtf\n", 4)                    = 4
exit_group(0)                           = ?

正如您所见,它会打开/dev/stdout(注意O_TRUNC)并获取FD 3,dup2以获取FD 3到FD 1,关闭FD 3,检查FD 1并获取大小为0 st_size=0,写入并退出。

如果你执行| cat >>,那么第二个进程会将FD 1连接到一个管道,这个管道不可搜索或截断...

注意:我只显示生成的文件的相关行。