Ускорить grep и запись в файл

Aug 18 2020

Буду признателен за любую помощь. В настоящее время у меня есть 2 файла (оба отформатированы одинаково), и в каждом из них более 2 миллионов строк. Пример файлов ниже:

файл 1:

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

файл 2:

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

Обратите внимание, что первая строка в каждом файле отличается, поэтому я бы распечатал ее в файл 3:

00000001 YYYY

Чтобы выполнить описанный выше процесс, у меня есть сценарий bash, который:

  1. grep первые ВОСЕМЬ символов для файла 2.
  2. Я сравниваю эхо / вывод grep со строкой в ​​файле 1.
  3. ЕСЛИ они разные, записать строку (из файла 1) в файл 3.

Я хотел предоставить образец кода, но имейте в виду, я просто придумал его на лету, НО это та же концепция, что и мой сценарий. В настоящее время я нахожусь 24 часа и только в сети 240 тысяч из 2 миллионов. Как я могу эффективно это ускорить?

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 есть функция 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скриптом): только одна строка каждого файла находится в активной памяти - две сравниваемые строки.

Однако в Unix есть другие решения описанной проблемы. Также можно использовать пасту и awk:

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

Или, если числа в первом столбце действуют как индекс, вы можете использовать join и awk:

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

Или команда comm (подавление столбцов 1 и 3), если столбец 1 в каждом файле отсортирован, также будет работать:

comm -1 -3 file1 file2

Все три команды / конвейера Unix / Linux производят:

00000001 YYYY