在 bash 中使用重定向时,我发现了一个奇怪且完全出乎意料的行为,即使我设法解决它,我也想知道它为什么会发生。
如果我运行这个命令:{ echo wtf > /dev/stdout ; } >> wtf.txt
N 次,我希望看到填充了 N 个“wtf”的行。我在文件中发现的是一行。
我认为由于第一个命令是在 truncate 模式下打开/dev/stdout,然后该模式由第二个文件描述符(wtf.txt)继承,然后被完全擦除,但我想知道你们中的一些人可能会更好地解释它,如果这是正确的行为还是错误。
为了清楚起见,我使用的命令是不同的,但使用 echo 示例更容易理解。原始命令是一个需要输出文件作为参数的命令,因为我想要 stdout 上的输出,所以我将/dev/stdout 作为参数传递。可以使用命令 openssl rand -hex 4 -out /dev/stdout >> wtf.txt
验证相同的行为。
最后,我设法通过以下方式解决了将附加操作委托(delegate)给 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 1 与 FD 3 复制并关闭 FD 3。此时它 fork (克隆),等待它退出并退出自身。
第二个进程
{ 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 连接到管道,该管道不可搜索或可截断...注意:我只显示了 strace 生成的文件的相关行。
关于bash - bash 重定向中的意外行为,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33563896/