Bash

作為 for 循環的一部分寫入同一文件會生成一個空文件

  • June 9, 2020

我正在編寫一個命令,將一些文本添加到與特定模式匹配的一堆文件中:

for file in $(find . -name "*.txt"); do sed "1s/^/hello/" $file; done 

如果我寫入stdout或寫入不同的文件(例如"$file.bak"),一切都會按計劃進行,但是當我嘗試讓命令寫回同一個文件時,文件的內容會被清除:

for file in $(find . -name "*.txt");do sed "1s/^/hello/" $file > $file; done

我發現這種行為令人驚訝,有人可以從概念上解釋為什麼會發生這種情況嗎?我在 macOS 上,我已經嘗試過這個bashzsh達到同樣的效果。

(請注意,我知道sed -i ""就地寫入,但我想在就地寫入之前將結果通過管道傳輸到不同的命令。)

概念上的驚喜可能在此聲明中

但是當我嘗試讓命令寫回同一個文件時

使用cmd file > file它時,它不是cmd打開要寫回的文件,而是打開外殼本身。shell 看到的第一件事是以> file寫入模式在位置 0 處打開文件(從而截斷它),然後將 stdout 重定向到該文件。所以此刻cmd開始讀取file它已經是空的。

或者,更正式一點:

  • Shell fork 一個新的程序來cmd執行
  • 新程序(仍在執行的 shell 程式碼)打開file以在位置 0 寫入(從而截斷它)
  • 新程序執行cmd,實際上是在目前程序中啟動一個新的二進製文件。
  • cmd以 stdout 指向執行file
  • cmd打開file閱讀,但此時它已經是空的

另一方面,如果您使用sed -i '1s/^/hello/' file該文件僅由sed(技術上在後台創建一個臨時文件)管理。

引用自:https://unix.stackexchange.com/questions/591855