Accelera grep e scrive su file

Aug 18 2020

Apprezzerei l'aiuto di chiunque. Attualmente, ho 2 file (entrambi formattati allo stesso modo) ed entrambi hanno oltre 2 milioni di righe ciascuno. Esempio di file di seguito:

file 1:

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

file 2:

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

Quindi nota che la prima riga in ogni file è diversa, quindi stamperei sul file 3:

00000001 YYYY

Per eseguire il processo sopra, ho uno script bash per:

  1. grep i primi OTTO caratteri per il file 2.
  2. Confronto l'eco / output di grep con la riga nel file 1.
  3. SE sono diversi, scrivi la riga (dal file 1) al file 3.

Volevo fornire un codice di esempio, ma tieni presente che l'ho appena inventato al volo MA è lo stesso concetto del mio script. Attualmente, sono in linea 24 ore e solo 240k su 2 milioni. Come posso velocizzarlo in modo efficiente?

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"

Risposte

5 dawg Aug 18 2020 at 11:06

Sarebbe così semplice con uno script Python.

Python ha la funzione zip che può essere utilizzata per leggere e confrontare due file riga per riga.

Script di Bash di esempio:

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

Stampe:

00000001 YYYY

Il vantaggio qui (su un semplice awkscript per esempio) solo una riga di ogni file è nella memoria attiva - le due righe vengono confrontate.

Tuttavia, Unix ha altre soluzioni al problema descritto. Puoi anche usare pasta e awk:

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

O se i numeri nella prima colonna agiscono come un indice, puoi usare join e awk:

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

Oppure il comando comm (sopprimendo col 1 e col 3) se la colonna 1 in ogni file è ordinata funzionerà anche:

comm -1 -3 file1 file2

Tutti e tre i comandi / pipe Unix / Linux producono:

00000001 YYYY