2011-10-28 30 views
16

當我試圖理清一個文件並保存排序輸出本身,這樣爲什麼「sort file1> file1」不起作用?

sort file1 > file1; 

的文件1的內容得到完全消除,而當我試圖做「三通」一樣這樣命令

sort file1 | tee file1; 

它工作正常 [ED:「正常工作」僅用於與幸運定時小文件,將造成路數或無益的進程調度丟失的數據],即,它覆蓋排序file1的輸出本身並在標準outp上顯示UT。

有人可以解釋爲什麼第一個案件不工作?

+0

的Dup的(http://superuser.com/q/142504/7542) – outis

回答

13

它不起作用,因爲'>'重定向意味着截斷,並且爲了避免在重定向到文件之前將sort的整個輸出保留在內存中,bash在運行前截斷並重定向輸出sort。因此,file1文件的內容將被截斷,然後sort將有機會讀取它。

+0

在重新引導到文件之前,並不是「避免將整個輸出排序在內存中」,它不是'bash'特有的。定義的'>'的優先級意味着它在執行程序之前被評估,因此在所有shell中都是如此。 – EJP

1

Bash在讀取管道時打開一個新的空文件,然後調用排序。

在第二種情況下,tee在排序已經讀取內容後打開文件。

+0

「三通」打開它的文件在一些相對於'sort'打開文件的不確定時間。有時你很幸運,有時候你不幸。 「排序」沒有必要讀取所有內容,只是它已經首先打開文件。 – EJP

1

重定向具有更高的優先級。所以在第一種情況下,> file1首先執行並清空文件。

4

依靠這些命令中的任何一種來按預期方式工作是不明智的。

修改位置的文件的方法是修改後的版本寫入到一個新的文件,然後將新的文件重命名爲原來的名稱:

sort file1 > file1.tmp && mv file1.tmp file1 

這避免了讀取文件時,它的後問題已經部分修改,這可能會弄亂結果。它還可以正確處理錯誤;如果文件長度爲N字節,並且文件系統上只有N/2個字節的可用空間,則可以檢測到創建臨時文件時發生的故障,而不執行重命名。

或者,你可以重命名原始文件,然後閱讀並寫入到一個新的文件具有相同名稱:

mv file1 file1.bak && sort file1.bak > file1 

有些命令選項到位,修改文件(例如,perlsed都有-i選項(注意,sed的的-i選項的語法可能有所不同),但這些選項通過創建臨時文件的工作;它只是在內部做

+3

不錯 - 但'sort -o file1 file1'更簡單也更安全。 –

16

正如其他人所解釋的,問題是I/O重定向完成之前的sort c ommand被執行,因此在sort有機會閱讀它之前截斷該文件。如果你想一下,理由很明顯 - shell處理I/O重定向,並且必須在運行該命令之前執行該操作。

sort命令有「總是」(因爲至少第7版UNIX)支持的-o選項,以使之安全輸出到輸入文件之一:

sort -o file1 file1 file2 file3 

tee訣竅取決於時機和運氣(可能是一個小數據文件)。如果你有一個兆字節或更大的文件,我預計它會被tee命令破壞,至少部分是破壞性的。也就是說,如果文件足夠大,tee命令將打開文件以輸出,並在sort完成讀取之前將其截斷。

+2

+1。它總是支付閱讀手冊 –

1

第一個命令不工作(sort file1 > file1),使用重定向操作符(>>>)時,因爲殼創建/截斷文件,甚至調用sort命令之前,因爲它具有更高的優先級。

第二個命令有效(sort file1 | tee file1),因爲sort先從文件讀取行,然後將排序數據寫入標準輸出。

因此,使用任何其他類似的命令時,你應該避免進行讀取和寫入同一個文件時使用重定向操作符,但你應該使用相關就地編輯爲(例如exedsed),例如:

ex '+%!sort' -cwq file1 

或使用其他utils的諸如sponge

幸運的是sort存在-o參數,將結果寫入到該文件(由@Jonathan所建議的),因此該解決方案是直接的:sort -o file1 file1

-2

您可以使用此方法

sort file1 -o file1 

這將整理並回存到原始文件。此外,您還可以使用此命令來刪除重複的行:[?SORT清空我的檔案]

sort -u file1 -o file1 
+0

多年前已經提到。 –

+0

並沒有回答實際的問題。 – EJP