私のフォルダには5000個のファイルがあります。ファイル名はXX0000001~XX0005000です。
各ファイルから単語を取得し、その単語と他のファイル(target.txt)の次の行をgrepしようとしています。
私のXX*ファイルの中には、約30,000語が含まれています。
これを行う方法はありますか?
私は試した:
start_number=0000001
end_number=0005000
words_file=target.txt
output_folder="output_results"
mkdir -p "$output_folder"
for ((i=start_number; i <=end_number; i++)); do
filename="XX$(printf "%07d" "$i")"
output_file="$output_folder/output_${filename}.txt"
while read -r word; do
awk -v word="$word" '{for (i=1; i<=NF; i++) if($1 ~ word) {print; next}}' "$filename" >> "$output_file"
done < "$words_file"
done
これを行うより速い方法がありますか?私のターゲットファイルには何百万もの検索があります。正確なターゲットファイルサイズは20GB、106441678行です。
例: XX0000001 ファイルは次のようになります。
Big1 Big5 Big7 Big10 Big11
(そして単語が多すぎます。一部のXXファイルには最大30,000単語が含まれる場合があります。)
Target.txt ファイルは次のとおりです。
#Big1
This_is_a_file_containing_xxxxx
#Big2
This_is_a_file_containing_xxxxx
#Big3
This_is_a_file_containing_xxxxx
#Big4
This_is_a_file_containing_xxxxx
#Big5
This_is_a_file_containing_xxxxx
#Big6
This_is_a_file_containing_xxxxx
#Big7
This_is_a_file_containing_xxxxx
#Big8
This_is_a_file_containing_xxxxx
#Big9
This_is_a_file_containing_xxxxx
#Big10
This_is_a_file_containing_xxxxx
#Big11
This_is_a_file_containing_xxxxx
#Big12
This_is_a_file_containing_xxxxx
ベストアンサー1
私のフォルダには5000個のファイルがあります。ファイル名はXX0000001~XX0005000です。
ファイルセットを繰り返すには、for f in XX0*
ここと同じシェルglobを使用します。一連の数字を繰り返す必要がある場合、Bash は数字を 8 進数で表示するので、前の 0 に注意する必要があります。たとえば、ループを試して、数字を印刷して最後の数字を見てください。
start_number=0000001
end_number=0005000
for ((i=start_number; i <=end_number; i++)); do
echo $i
done |tail -1
出力はyes 2560
、noです5000
。しかし、zshではそうではなく、どのシェルを実行しているのか言及していませんが、問題は指摘する価値があります。
ここでは、
while read -r word; do
awk -v word="$word" '{for (i=1; i<=NF; i++) if($1 ~ word) {print; next}}' "$filename" >> "$output_file"
done < "$words_file"
これが何をしているのかはわかりませんが、AWKスクリプトでは入力行のすべてのフィールドを繰り返しますが、$1
ループ内ではフィールド1()のみを参照していることがわかりました。
ここで、ファイルが次のようになるとします。
% cat XX0000001
Big1 Big7
% cat XX0000002
Big5 Big10
% cat target.txt
#Big1
This_is_a_file_containing_xxxxx
#Big2
This_is_a_file_containing_xxxxx
[...]
Big1
つまり、ファイルの1行に複数の異なるパターン(たとえば、および)があります(たとえば、1行に1つずつ)。また、どのパターンにも一致する行を見つけて、次の行と一緒に印刷したいと思います。Big7
XX0*
target.txt
これで、標準のgrepは一致後に「1行」を印刷でき、同時に複数のパターンを見つけることができます。この-f
オプションは、行がパターンを形成するファイルの名前を使用するため、XX0*
各パターンが単一の行として表示されるようにファイルを前処理する必要があります。すべてのスペースを改行文字に変更するだけですtr
。最も簡単な方法は、プロセスオーバーライドを使用してtr
toの出力をgrep
ファイルとして使用することですが、一時ファイルを使用することもできます(または出力をtoにパイプすることもできますtr
)grep -f -
。
たとえば、
% grep -A1 -f <(tr ' ' '\n' < XX0000001 ) target.txt
#Big1
This_is_a_file_containing_xxxxx
--
#Big7
This_is_a_file_containing_xxxxx
--
#Big10
This_is_a_file_containing_xxxxx
もちろん、Big1
その行でもパターンが発生するため、#Big10
一致します。 (しかし、grepオプションを使用してフルワードマッチングを要求できます-w
。)区切り文字を削除するには、--
結果をパイプすることができますgrep -ve --
。
これがどれだけ効率的かはgrepの実装によって異なりますが、この目的のために設計されたツールとして、シェルスクリプトで同じことを行うよりも最適化の可能性が高くなります。シェルスクリプトは遅いです。すべてのパターンがフォーマットであれば、Big*
共通部分を一度だけ見つけることが賢明です。パターンリストを単一のパターンに変更することもできます。Big(1|5|7|10)
正規表現エンジンでうまく機能できることを願っています。