Acelere grep y escritura en archivo

Aug 18 2020

Agradecería la ayuda de cualquiera. Actualmente, tengo 2 archivos (ambos con el mismo formato) y ambos tienen más de 2 millones de líneas en cada uno. Ejemplo de archivos a continuación:

archivo 1:

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

archivo 2:

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

Así que observe que la primera línea en cada archivo es diferente, por lo que imprimiría en el archivo 3:

00000001 YYYY

Para hacer el proceso anterior, tengo un script bash para:

  1. grep los primeros OCHO caracteres para el archivo 2.
  2. Comparo el eco / salida del grep con la línea en el archivo 1.
  3. SI son diferentes, escriba la línea (del archivo 1) al archivo 3.

Quería proporcionar un código de muestra, pero tenga en cuenta que lo inventé sobre la marcha, PERO es el mismo concepto que mi script. Actualmente, estoy 24 horas dentro y solo en línea 240k de 2 millones. ¿Cómo puedo acelerar esto de manera eficiente?

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"

Respuestas

5 dawg Aug 18 2020 at 11:06

Esto sería tan simple con un script de Python.

Python tiene la función zip que se puede usar para leer y comparar dos archivos línea por línea.

Ejemplo de script 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])'

Huellas dactilares:

00000001 YYYY

La ventaja aquí (sobre un awkscript simple, por ejemplo) solo una línea de cada archivo está en la memoria activa: las dos líneas se comparan.

Sin embargo, Unix tiene otras soluciones al problema descrito. También puede utilizar pegar y awk:

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

O si los números de la primera columna actúan como un índice, puede usar join y awk:

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

O el comando comm (suprimiendo la columna 1 y la columna 3) si la columna 1 de cada archivo está ordenada, también funcionará:

comm -1 -3 file1 file2

Los tres comandos / tuberías de Unix / Linux producen:

00000001 YYYY