Bashスクリプトでcatとxargsのパフォーマンスを向上させる方法

Bashスクリプトでcatとxargsのパフォーマンスを向上させる方法

以下を呼び出して、100万のフィールド行を含むファイルを処理する必要があります。

1m.txt

これで、私のスクリプトは1m.txtに含まれている行を検証します。

cat out.txt > advance.txt 2> /dev/null
cat 1m.txt | xargs -I {} -P 100 sh -c "if ! grep --quiet {} advance.txt; then if host {} >/dev/null; then echo OK {}; else echo DIE {}; fi; fi" >> out.txt

このスクリプトが行うことは、中断(ctrl + c)されてから再開されると、処理された最後の行から始まるということです。行が1,000行の場合、200行で中断されたプロセスはすばやく再開されます。ただし、100万行の場合、500,000行のプロセスを中断するには数時間かかります。

もっと効率的にする方法はありますか?

ベストアンサー1

したがって、現在のロジックについては、「1m.txtの各行にすでにadvance.txtがあることを確認してください。そうでない場合はそれを処理してout.txtに追加します。操作が開始されたら、advance.txtを含むすべての行に更新します。 out.txt '。

問題は、advance.txtに行が増えるほど、それぞれを比較する必要がある行が増えることです。最悪のシナリオでは、すべての行が処理される場合は、1m.txtの百万行をすべてチェックして、advance.txtであることを確認する必要があります。平均して、advance.txt行の半分を比較する必要があるため、1,000,000×500,000または500,000,000,000(5000億)回の比較が必要です。

並列に処理しない場合、これを処理する簡単な方法は、out.txtで最後の行を見つけて、1m.txtからそのポイントまでのすべての行をスキップすることです。例えば

# Pipe the output of the if/then/else/fi construct to xargs.
# use the if/then/else/fi to select the input.
# Use '-s' to see if the file exists and has non zero size.
 if [ -s out.txt ] ; then
    # we have some existing data
    # Get the host from the last line
    # delete anything that is not the last line
    # remove the DIE/OK. quote anything not alphabetic with a backslash.
   lasthost="$(sed '$!d;s/^\(DIE\|OK\) //;s/[^0-9a-zA-Z]/\\&/g' out.txt)"
   # get the lines from 1m.txt from after the matched host
   # uses GNU sed extension to start at line "0"
   sed "0,/^$lasthost\$/d" 1m.txt
 else
   # no existing data, so just copy the 1m.txt using cat
   cat 1m.txt
 fi | xargs -I {} sh -c "if host {} >/dev/null; then echo OK {}; else echo DIE {}; fi" >> out.txt

しかし、タスクを並列に処理しています。host戻り値は異なる時間がかかる可能性があるため、入力を大幅に並べ替えることができます。ホストが検証されたかどうかを確認するより高速な方法が必要です。標準的なアプローチは、ある種のハッシュテーブルを使用することです。 1つの方法はを使用することですawk

 if [ -s out.txt ] ; then
    # we have some existing data. Process the two files given
    # for the first file set the entries of the seen array to 1
    # for the second file print out the hosts which have not been seen. 
    awk 'FNR==NR {seen[$2]=1;next} seen[$1]!=1' out.txt 1m.txt
 else
   cat 1m.txt
 fi | xargs -I {} -P 100 sh -c "if host {} >/dev/null; then echo OK {}; else echo DIE {}; fi" >> out.txt

おすすめ記事