[英]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 cmd
和xargs 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
進程,而沒有n1
, xargs
啟動更少的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.