2015-11-06 58 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的相關線路產生。