grepとファイルへの書き込みを高速化

Aug 18 2020

誰かの助けをいただければ幸いです。現在、2つのファイル(どちらも同じ形式)があり、どちらもそれぞれ200万行を超えています。以下のファイルの例:

ファイル1:

00000001 YYYY
00000002 NYNN
00000003 YNYN
...
...

ファイル2:

00000001 YYNY
00000002 NYNN
00000003 YNYN
...
...

したがって、各ファイルの最初の行が異なることに注意してください。ファイル3に出力します。

00000001 YYYY

上記のプロセスを実行するために、次のbashスクリプトがあります。

  1. ファイル2の最初の8文字をgrepします。
  2. grepのエコー/出力をファイル1の行と比較します。
  3. それらが異なる場合は、(ファイル1からの)行をファイル3に書き込みます。

サンプルコードを提供したかったのですが、覚えておいてください。これはその場で作成しただけですが、スクリプトと同じ概念です。現在、私は24時間勤務しており、200万人のうち24万人しかオンラインにいません。どうすればこれを効率的にスピードアップできますか?

input="file1"
while IFS= read -r line
do
LineFromFile1=$("${echo $line}") firstEightChars=$("${echo $line:0:8}")
if grep -q "$firstEightChars" file2; then $LineFoundInFile2="$(grep $firstEightCharst file2)"
  if [[ $line == $LineFoundInFile2 ]]; then
    :
  else
    echo $line >> file3 done < "$input"

回答

5 dawg Aug 18 2020 at 11:06

これは、Pythonスクリプトを使用すると非常に簡単になります。

Pythonには、2つのファイルを1行ずつ読み取って比較するために使用できるzip関数があります。

Bashスクリプトの例:

echo '00000001 YYYY
00000002 NYNN
00000003 YNYN' >file1


echo '00000001 YYNY
00000002 NYNN
00000003 YNYN' >file2

python3 -c '
with open("file1") as f_1, open("file2") as f_2:
   for t in zip(f_1, f_2):
      if t[0][8:-1] != t[1][8:-1]: print(t[0])'

プリント:

00000001 YYYY

ここでの利点(awkたとえば、単純なスクリプトに対する)は、各ファイルの1行だけがアクティブメモリにあり、2行が比較されます。

ただし、Unixには、説明されている問題に対する他の解決策があります。貼り付けとawk:を使用することもできます

paste file1 file2 | awk '$2!=$4 {print $1 OFS $2}'

または、最初の列の数値がインデックスとして機能している場合は、joinとawkを使用できます。

join file1 file2 | awk '$2!=$3 {print $1 OFS $2}'

または、各ファイルの列1がソートされている場合は、commコマンド(列1と列3を抑制)も機能します。

comm -1 -3 file1 file2

3つのUnix / Linuxコマンド/パイプはすべて次のものを生成します。

00000001 YYYY