Linux 中的管道/重定向到底是如何運作的?

Linux 中的管道/重定向到底是如何運作的?

我有這三個重定向 stdin/stdout 的範例,其中只有一個按預期方式工作。如果有人能向我解釋這一點,我會很高興。

目標是對 file1 中的內容進行排序並將變更儲存到同一文件中。

  1. 排序文件 1 | tee file1 > /dev/null --------> 它有效

  2. 排序文件 1 | tee file1 --------> file1 的內容將會被刪除

  3. 排序文件 1 | tee file1 > file2 --------> file1 的內容將會被刪除

附言。 tee 將標準輸入複製到每個文件,也複製到標準輸出。

第一個例子的工作原理是什麼?

答案1

根據我在 Debian Wheezy 上的測試,所有 3 個場景都可能導致兩種結果(file1 被排序並寫回自身,或者沒有任何內容被排序並且沒有任何內容寫入 file1。

我相信這是正常行為,來自 Linux 處理文件的方式。考慮一下該命令 - sort 命令開始讀取 file1 並立即將其輸出傳送至 tee。 Tee 讀取輸出,將其寫回 file1 並將其列印到 /dev/null。如果 sort 夠快來讀取整個檔案1,則 tee 會得到排序的輸出。但是,如果 tee 獲得了對文件的鎖定,它會刪除它(tee 總是刪除輸出文件,除非使用追加選項),這幾乎就是所有 3 個場景中發生的情況。

為了使其更短,可以說,有時排序速度不夠快,無法讀取 file1。在這種情況下,tee 在 sort 可以讀取檔案之前擦除該檔案。

我建議採用以下程序:

cat file1 | sort > /tmp/sorting.tmp; mv /tmp/sorting.tmp file1

如果您想在 stdout 上查看排序後的輸出,請按如下操作:

cat file1 | sort | tee /tmp/sorting.tmp; mv /tmp/sorting.tmp file1

在多處理器系統上讓 2 個不同的命令處理 1 個檔案並不是一個好主意 - 您永遠無法確定哪個命令首先執行。在單執行緒系統上,行為會有所不同 - 順序的。

答案2

我懷疑這種行為是可預測的(而且肯定不會依賴它)。該tee命令可能會啟動一個新進程以將其輸入傳送到「其他」目的地。作業系統將「緩衝」輸出,直到它到達建立目標檔案並將其臨時緩衝區寫入該檔案的位置。這種情況發生(並覆蓋原始程式碼)的確切時刻可能取決於:

  • 檔案的大小和緩衝區的可用內存
  • 經過的時間
  • 如果從管道輸入tee完成

這比bash:這是程式啟動的方式bash。 shell 只是解釋您輸入的命令,並啟動執行命令所需的程式。 shell 無法控制每個程式如何運作,更無法控制這些程式如何互動。要求一個程式(或一組程式)從輸入檔案中取得數據,並在同一個句子中將結果寫入到同一輸入檔案中,這是使用者的責任。

不要忘記bash只是用戶命令的解釋器:它只是shell圍繞作業系統將用戶意圖轉換為系統呼叫。

這是記錄在案, 也!或者這封郵件,它解決了類似的問題。或這個StackOverflow線程。或者這個伺服器故障線程

stdin請注意,如果您從檔案: 中取得輸入命令,則重定向 : $ myprog < commandfile也可能會發生這種情況。如果myprog寫入命令文件,則不能保證所有commandfile命令都會執行。

一個非常基本的類比是這樣的指令列表:

- Execute the instructions step by step
- Dip this instruction list in a bucket of black paint
- Type in the following commands:
  find /etc -type f -exec cat '{}' \; | tr -c '.[:digit:]' '\n' \
  | grep '^[^.][^.]*\.[^.][^.]*\.[^.][^.]*\.[^.][^.]*$'

我想你會先影印一份嗎? (命令取自進階 Bash 腳本指南

答案3

那麼您希望保留文件的原始內容,同時附加更改後的文件嗎?

預設情況下,tee 會覆蓋寫入,請嘗試使用 -a 標誌將變更附加到檔案中。

答案4

sort file1 | tee file1 > tmp && mv file1 original && mv tmp file1

您可以將檔案寫入佔位符,將原始檔案重新命名為備份,然後將佔位符移至原始檔案。

相關內容