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的

最佳答案 你可以检查一下使用strace会发生什么:

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

在我的例子中,这将生成两个文件,如wtf-trace.txt.12889和wtf-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 3复制FD 1并关闭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的文件,写入它并退出.

如果你这样做猫>>然后第二个过程得到FD 1连接到管道,这是不可寻找或截断…

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

点赞