Acelere o grep e a gravação no arquivo

Aug 18 2020

Eu apreciaria a ajuda de alguém. Atualmente, tenho 2 arquivos (ambos formatados da mesma forma) e ambos têm mais de 2 milhões de linhas em cada um. Exemplo de arquivos abaixo:

arquivo 1:

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

arquivo 2:

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

Portanto, observe que a primeira linha em cada arquivo é diferente, então eu imprimiria no arquivo 3:

00000001 YYYY

Para fazer o processo acima, tenho um script bash para:

  1. grep os primeiros OITO caracteres para o arquivo 2.
  2. Eu comparo o eco / saída do grep com a linha no arquivo 1.
  3. SE eles forem diferentes, escreva a linha (do arquivo 1) no arquivo 3.

Eu queria fornecer um código de amostra, mas lembre-se, acabei de inventar isso na hora, MAS é o mesmo conceito do meu script. Atualmente, estou 24 horas em e apenas na linha 240k de 2 milhões. Como posso acelerar isso de forma 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"

Respostas

5 dawg Aug 18 2020 at 11:06

Isso seria tão simples com um script Python.

Python tem a função zip que pode ser usada para ler e comparar dois arquivos linha por linha.

Exemplo 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])'

Impressões:

00000001 YYYY

A vantagem aqui (sobre um awkscript simples, por exemplo) apenas uma linha de cada arquivo está na memória ativa - as duas linhas sendo comparadas.

No entanto, o Unix tem outras soluções para o problema descrito. Você também pode usar colar e awk:

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

Ou se os números na primeira coluna estiverem agindo como um índice, você pode usar join e awk:

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

Ou o comando comm (suprimindo a coluna 1 e a coluna 3) se a coluna 1 em cada arquivo for classificada também funcionará:

comm -1 -3 file1 file2

Todos os três comandos / canais Unix / Linux produzem:

00000001 YYYY