2016-12-28 186 views
3

給定一個包含幾百萬個文件的目錄,我們希望從這些文件中提取一些數據。命令輸出重定向

find /dir/ -type f | awk -F"|" '$2 ~ /string/{ print $3"|"$7 }' > the_good_stuff.txt

這不會放大,所以我們介紹xargs的。

find /dir/ -type f -print0 | xargs -0 -n1 -P6 awk -F"|" '$2 ~ /string/{ print $3"|"$7 }'

這將產生有效的輸出,無論我們多長時間運行。 Sweet可以通過在該命令上附加> the_good_stuff_from_xargs.txt來將它寫入文件。除了現在文件包含損壞的行。

讓我感到震驚的是,在查看xargs在我的終端中作爲STDOUT打開的六個子進程的輸出時,數據看起來很好。數據重定向到文件系統的時刻是出現損壞的時刻。

我試圖追加以下命令。

> myfile.txt

>> myfile.txt

| mawk '{print $0}' > myfile.txt

並重定向或以其他方式的其他各種概念它與數據中的每個版本被損壞寫入磁盤之前「池」的xargs的的輸出。

我很積極的原始文件沒有格式錯誤。我確信,當在終端中查看標準輸出時,xargs的命令產生有效輸出,長達10分鐘盯着它吐出文本...

本地磁盤是SSD ......我正在讀寫來自同一個文件系統。

爲什麼重定向find /dir/ -type f -print0 | xargs -0 -n1 -P6 awk -F"|" '$2 ~ /string/{ print $3"|"$7 }'的輸出會導致數據變得格式錯誤?

編輯

我目前還不能安裝無緩衝,但stdbuf -oL -eL修改命令的輸出進行行緩衝,因此,從理論上說,應該做同樣的事情。

我試過stdbuf xargs cmdxargs stdbuf cmd這兩個都導致了非常虛線。

-P6是必需的,才能在任何合理的時間內完成此命令。

EDIT 2

爲了澄清... xargs和它的-P6標誌是要解決的問題,因爲我們的工作目錄中的有一萬必須掃描文件的要求。

顯然,我們可以刪除-P6或以其他方式停止運行一次多個就業機會,而且這不是真正回答的爲什麼輸出越來越錯位也不是一個現實的方法輸出如何是問題恢復到「正確」的狀態,同時仍然完成規模的任務。

解決方案

接受的答案使用parallel其工作過的最好的了所有的答案提及。

我跑的最後一個命令看起來像。 time find -L /dir/ -type f -mtime -30 -print0 | parallel -0 -X awk -f manual.awk > the_good_stuff.txt awk很困難,所以我將-F"|"轉移到命令本身。默認情況下,並行會爲每個核心啓動一個作業,如果需要,可以使用-j來設置較低的作業數量。

用真正的科學術語來說,這是一個巨大的速度增加。經過6分鐘6分鐘後,未經測量的小時數(可能爲6+)是10%,因此可能在一小時內完成。

一個問題是,您必須確保在parallel中運行的命令不會嘗試寫入文件...,以便有效地繞過並行執行的作業的輸出處理!

最後沒有-X平行行爲類似於xargs -n1

+2

標準輸出在寫入終端時被行緩衝,但在寫入管道或文件時被完全緩衝。 – Barmar

+0

使用'Expect'附帶的'unbuffer'命令。 – Barmar

+5

刪除'-P6';這會導致6個異步進程隨機寫入輸出,並且在緩衝區填充時寫入部分行,並且不同的進程在不同的位置寫入不同的局部行等。如果您必須使用-P6,則需要具有這6個進程寫入不同的文件,以便它們不會對彼此的輸出進行踐踏。這反過來可能意味着運行一個運行'awk'的shell腳本,並將I/O重定向到一個單獨的文件(使用'mktemp',可能是基於腳本PID的名稱)。 –

回答

2

man xargsman xargs提到這個問題:「請注意,這取決於被調用的進程是否正確地管理對共享資源的並行訪問,例如,如果它們中有多個嘗試打印到stdout,則會生成ouptut不確定的順序(而且很有可能混淆)」

幸運的是,有一種方法,使這項操作一個量級更快解決,同時是混淆的問題:

find /dir/ -type f -print0 | xargs -0 awk -F"|" '$2 ~ /string/{ print $3"|"$7 }' 

爲什麼呢?

-P6正在洗牌您的輸出,所以不要使用它。 xargs -n1推出一個awk過程中的每個文件,而無需n1xargs推出少很多awk過程,就像這樣:

files | xargs -n1 awk 
=> 
awk file1 
awk file2 
... 
awk fileN 

vs 

files | xargs awk 
=> 
awk file1 file2 ... fileN # or broken into a few awk commands if many files 

我跑〜20K的文字代碼文件中的每個〜20K大小,有和沒有-n1 -P6

with -n1 -P6 23.138s 
without  3.356s 

,如果你想不xargs的標準輸出洗牌並行,使用GNU parallel(也由戈登·戴維森建議),如:

find /dir/ -type f -print0 | parallel --xargs -0 -q awk -F"|" '$2 ~ /string/{ print $3"|"$7 }' 

注:-q必須引用命令字符串,否則-F"|"和周圍的awk代碼的報價成爲不帶引號的時候parallel運行它們。

parallel節省了一些時間,但不如開溝-n1那樣:

parallel  1.704s 

PS:引入cat(馬特確實在他的回答)不僅僅是xargs awk一個微小的速度更快:

xargs awk  3.356s 
xargs cat | awk 3.036s 
+1

嗯,我應該放棄'-n1'我認爲這是從試圖解開數據的嘗試中遺留下來的。我不介意輸出的順序是否混合。當輸出「損壞」時,我會介意,半行寫入,另一半寫入另一行......無論哪種方式,我都會嘗試您的建議並報告結果。 –

0

我只想做到以下幾點:

cat /${dir}/* | awk '$2 ~ /string*/{ print $3 "|" $7 }' >> `date`.txt 

當文件在該進程中運行的日期和時間命名。

+1

我可能是錯的,但如果在$ {dir}裏有一個目錄,這會破壞嗎?和OP一樣,使用「find -f」通常是獲取文件的好方法。它甚至會遞歸地發現它們是哪個貓和一個glob模式不會做的。 – diametralpitch

+1

這個答案忽略了我們試圖運行多個awk命令以提高從文件中選擇「字符串」的速度的要求。 –

+0

它不下降到子目錄(這是沒有要求)。我們忽略了以這種方式執行查找類型的必要性。 – Matt