簡體   English   中英

命令輸出在重定向時損壞

[英]Command output mangled on redirection

給定一個包含幾百萬個文件的目錄,我們想從這些文件中提取一些數據。

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 }'

無論我們運行多久,這都會產生有效的輸出。 很好,所以我們可以通過在該命令上附加一個> the_good_stuff_from_xargs.txt將其寫入文件。 除了現在文件包含損壞的行。

令我印象深刻的是,在查看xargs在我的終端中作為STDOUT打開的六個子進程的輸出時,數據看起來很好。 數據重定向到文件系統的那一刻就是出現損壞的時候。

我嘗試使用以下命令附加命令。

> myfile.txt

>> myfile.txt

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

以及在將xargs的輸出寫入磁盤之前重定向或以其他方式“匯集”xargs的輸出的各種其他概念,其中每個版本中的數據都被破壞。

我很肯定原始文件沒有格式錯誤。 我很肯定當在終端中查看為stdout時,帶有xargs的命令會產生有效輸出,最多可持續10分鍾盯着它吐出文本...

本地磁盤是一個SSD ...我正在從同一個文件系統讀取和寫入。

為什么重定向find /dir/ -type f -print0 | xargs -0 -n1 -P6 awk -F"|" '$2 ~ /string/{ print $3"|"$7 }' find /dir/ -type f -print0 | xargs -0 -n1 -P6 awk -F"|" '$2 ~ /string/{ print $3"|"$7 }' find /dir/ -type f -print0 | xargs -0 -n1 -P6 awk -F"|" '$2 ~ /string/{ print $3"|"$7 }'導致數據格式錯誤?

編輯

我目前無法安裝unbuffer,但stdbuf -oL -eL修改了命令輸出為行緩沖,因此理論上應該做同樣的事情。

我已經嘗試過兩個stdbuf xargs cmdxargs stdbuf cmd都導致了極其破碎的線條。

為了使該命令在任何合理的時間內完成,需要-P6

編輯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 time find -L /dir/ -type f -mtime -30 -print0 | parallel -0 -X awk -f manual.awk > the_good_stuff.txt awk很難,所以我移動了-F"|" 進入命令本身。 默認情況下,parallel會在框中為每個核心啟動一個作業,如果需要,可以使用-j設置較低的作業數。

從科學的角度來說,這是一個巨大的速度提升。 花費了不可測量的小時數(可能是6小時)是在6分鍾后完成10%,因此很可能在一小時內完成。

一個問題是你必須確保parallel運行的命令沒有嘗試寫入文件...這有效地繞過了並行對其運行的作業執行的輸出處理!

最后沒有-X並行動作類似於xargs -n1

man 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的stdout shuffling的parallel ,可以使用gnu parallel (也是由Gordon Davisson建議的),例如:

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

注意: -q是引用命令字符串所必需的,否則引用-F"|" parallel運行它們時, awk代碼周圍變得不帶引號。

parallel節省了一點時間,但沒有像-n1那樣放棄了:

parallel       1.704s

ps:介紹一只cat (Matt在他的回答中做的)比xargs awk快一點:

xargs awk        3.356s
xargs cat | awk  3.036s

我會做以下事情:

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

文件的名稱取決於運行進程的日期和時間。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM