我在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的相关行.