2015-11-06 35 views
4

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

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

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

只是要清楚,我使用的命令是一个不同的,但与回声示例更容易理解它。原始命令是一个需要输出文件作为参数的命令,并且由于我希望stdout上的输出通过/dev/stdout作为参数。使用命令openssl rand -hex 4 -out /dev/stdout >> wtf.txt可以验证相同的行为。

最后,解我设法解决这个问题通过以下方式委托追加操作发球{ echo wtf > /dev/stdout } | tee -a wtf.txt > /dev/null

+1

这是因为重定向'>> wtf.txt'首先发生,然后,当处理'>/dev/stdout'时,由于使用'>'而不是''>,所以不再追加到stdout >'。所以,它的工作原理:'{echo wtf >>/dev/stdout; } >> wtf.txt' – whoan

+0

认为你正在做类似于'echo wtf >> wtf.txt> wtf.txt'。用'>> wtf.txt'你可以将'/ dev/stdout' *指向* wtf.txt。然后,用'>/dev/stdout'替换之前的重定向。 '/ dev/stdout'在这里是'wtf.txt'的符号链接。 – whoan

+0

不能在bash 3.2或bash 4.3中重现,要么通过手动或在循环内快速运行N个命令中的每一个。 – chepner

回答

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)       = ? 

第一个进程打开或追加并获得FD 3.之后,它复制FD 1 FD 3和FD关闭在这一点创建“wtf.txt”它叉(克隆),等待它退出并退出。

{ echo wtf > /dev/stdout }通过FD 1(标准输出)继承了文件,它的第二个过程:

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的相关线路产生。