拆分文件,將每個部分作為參數傳遞給腳本,並行執行每個腳本
我有一個包含 10000 個單詞的 words.txt(一行一行)。我有 5,000 份文件。我想查看哪些文件包含哪些單詞(單詞周圍有一個正則表達式模式)。我有一個 greps 文件和輸出命中的 script.sh。我想 (1) 將我的輸入文件拆分為較小的文件 (2) 將每個文件作為參數提供給 script.sh 並 (3) 並行執行所有這些。
我基於教程的嘗試遇到了錯誤
$parallel ./script.sh ::: split words.txt # ./script.sh: line 22: split: No such file or directory
我的 script.sh 看起來像這樣
#!/usr/bin/env bash line 1 while read line line 2 do some stuff line 22 done < $1
我想我可以通過啟動 grep 命令的目錄中的文件將拆分輸出到目錄循環 - 但是如何優雅而簡潔地做到這一點(使用並行)?
您可以使用該
split
工具:split -l 1000 words.txt words-
會將您的
words.txt
文件拆分為每個命名不超過 1000 行的文件words-aa words-ab words-ac ... words-ba words-bb ...
如果省略前綴(
words-
在上面的範例中),則split
用作x
預設前綴。要使用生成的文件,
parallel
您可以使用 glob:split -l 1000 words.txt words- parallel ./script.sh ::: words-[a-z][a-z]
您可能不需要臨時文件,因為您從 STDIN 讀取。所以真的沒有理由使用
split
. 通過使用擺脫文件--pipe
:cat words | parallel --pipe -L 1000 -N1 ./script.sh
如果它真的只是你想要的 grep:
find dir-with-5000-files -type f | parallel -X grep -f words.txt
如果
words.txt
太大而無法放入記憶體,您可以將其拆分:find dir-with-5000-files -type f | parallel -X "cat words.txt | parallel --pipe grep -f -"
GNU Parallel 的手冊頁涵蓋瞭如何最有效地為 m 正則表達式 grep n 行:http ://www.gnu.org/software/parallel/man.html#example__grepping_n_lines_for_m_regular_expressions_
為大量正則表達式 grep 大文件的最簡單解決方案是:
grep -f regexps.txt bigfile
或者,如果正則表達式是固定字元串:
grep -F -f regexps.txt bigfile
有 2 個限制因素:CPU 和磁碟 I/O。CPU 很容易測量:如果 grep 佔用 >90% CPU(例如在執行 top 時),那麼 CPU 是一個限制因素,並行化將加快這一程序。如果不是,那麼磁碟 I/O 是限制因素,並且取決於磁碟系統,並行化可能更快或更慢。唯一確定的方法是測量。
如果 CPU 是限制因素,則應在正則表達式上進行並行化:
cat regexp.txt | parallel --pipe -L1000 --round-robin grep -f - bigfile
這將為每個 CPU 啟動一個 grep 並為每個 CPU 讀取一次大文件,但由於這是並行完成的,除第一個之外的所有讀取都將記憶體在 RAM 中。根據 regexp.txt 的大小,使用 –block 10m 而不是 -L1000 可能更快。如果 regexp.txt 太大而無法放入 RAM,請刪除 –round-robin 並調整 -L1000。這將導致大文件被讀取更多次。
一些儲存系統在並行讀取多個塊時性能更好。這適用於某些 RAID 系統和某些網路文件系統。並行讀取大文件:
parallel --pipepart --block 100M -a bigfile grep -f regexp.txt
這會將大文件拆分為 100MB 的塊並在每個塊上執行 grep。要並行讀取 bigfile 和 regexp.txt,請使用 –fifo 將兩者結合起來:
parallel --pipepart --block 100M -a bigfile --fifo cat regexp.txt \ \| parallel --pipe -L1000 --round-robin grep -f - {}