Confronta due file con la prima colonna e rimuovi la riga duplicata dal 2o file nello script della shell


9

Farò la mia domanda con un esempio. Ho 2 file:

File n. 1:

118D FC300_R5_TP  FX.B      32775       2112   6       2038   6       2112   0
118E FC300_R5_TP  FX.B      32775       2136   7       2065   6       2136   0
118F FC300_R5_TP  FX.B      32775       2124   6       2064   6       2124   0
1190 FC300_R5_TP  FX.B     819210     814632  99     814609  99     814632   0
1191 FC300_R5_TP  FX.B     819210     104100  13     103714  13     104100   0
1192 FC300_R5_TP  FX.B    1638420    1609476  98    1609402  98    1609476   0
1196 FC300_R5_TP  FX.B    1638420    1638432 100    1638379 100    1638432   0
119A FC300_R5_TP  FX.B    3276840    3271776 100    3271698 100    3271776   0
119E FC300_R5_TP  FX.B    3276840    3264120 100    3264034 100    3264120   0
11A2 FC300_R5_TP  FX.B    3276840    2328648  71    2328546  71    2328648   0
11A6 FC300_R5_TP  FX.B    3276840    2328444  71    2328355  71    2328444   0
11AA FC300_R5_TP  FX.B    3276840    2328528  71    2328403  71    2328528   0
11AE FC300_R5_TP  FX.B    3276840    2328648  71    2328468  71    2328648   0
11B2 FC300_R5_TP  FX.B    3276840    2130000  65    2129766  65    2130000   0
173A FC300_R5_TP  FX.B    6553680    6478572  99    6477747  99    6478572   0

File n. 2:

11AA FC300_R5_TP  FX.B    3276840    2328528  71    2328403  71    2328528   0
11AE FC300_R5_TP  FX.B    3276840    2328648  71    2328468  71    2328648   0
11B2 FC300_R5_TP  FX.B    3276840    2130000  65    2129766  65    2130000   0
173A FC300_R5_TP  FX.B    6553680    6478572  99    6477747  99    6478572   0
0BDB FC600_R5_TP  FX.B   33554640    6044364  18    6033105  18    6044364   0
0BDC FC600_R5_TP  FX.B   33554640    6613536  20    6481974  19    6613536   0
0BDD FC600_R5_TP  FX.B   33554640    4435848  13    4057170  12    4435848   0
0BDE FC600_R5_TP  FX.B   33554640    6620868  20    6249518  19    6620868   0

Uscita desiderata

File n. 3:

0BDB FC600_R5_TP  FX.B   33554640    6044364  18    6033105  18    6044364   0
0BDC FC600_R5_TP  FX.B   33554640    6613536  20    6481974  19    6613536   0
0BDD FC600_R5_TP  FX.B   33554640    4435848  13    4057170  12    4435848   0
0BDE FC600_R5_TP  FX.B   33554640    6620868  20    6249518  19    6620868   0

Vorrei confrontare il file 1 e il file 2 usando le loro prime colonne e rimuovere l'intera riga o riga dal file 2 in cui corrispondono nel file 1. Vorrei anche salvare i risultati in un terzo file, file # 3.

Risposte:


10

Puoi usare awkper questo:

awk 'FNR==NR{a[$1];next};!($1 in a)' file1 file2 > file3

Spiegazione:

  • FNR == NR: Questo test è vero quando il numero di record è uguale al numero di record nel file. Questo vale solo per il primo file, poiché il secondo file NRsarà uguale al numero di righe di file1 + FNR.

  • a[$1]: Crea un indice di elemento array del primo campo di file1.

  • next: passa al record successivo, quindi non viene più eseguita l'elaborazione su file1.

  • !($1 in a): Verifica se il primo campo ($ 1) è presente nell'array, ovvero in file1, e stampa l'intera riga (su file3).

Basato su uno degli esempi del wiki #awk .


Risposta perfetta !!!
mtk

8
export LC_ALL=C
comm -13 <(sort f1) <(sort  f2)

Riporterebbe le righe che sono solo in f2.

export LC_ALL=C
join -v2 <(sort f1) <(sort f2)

Riporterebbe le righe del f2cui primo campo non viene trovato come primo campo in nessuna riga di f1.

(è necessaria una shell con supporto per la sostituzione di processo come ksh93, zsho bash).


2

Solo per divertimento ecco una soluzione in Perl:

#!/usr/bin/perl

# create names lookup table from first file
my %names;
while (<>) {
    (my $col1)= split / /, $_;
    $names{$col1} = 1;
    last if eof;
}

# scan second file
while (<>) {
    print if /^(\S+).*/ && not $names{$1};
}

Esempio

$ ./showdiffs.pl file1  file2
0BDB FC600_R5_TP  FX.B   33554640    6044364  18    6033105  18    6044364   0
0BDC FC600_R5_TP  FX.B   33554640    6613536  20    6481974  19    6613536   0
0BDD FC600_R5_TP  FX.B   33554640    4435848  13    4057170  12    4435848   0
0BDE FC600_R5_TP  FX.B   33554640    6620868  20    6249518  19    6620868   0

Dettagli

La soluzione Perl sopra è composta da 2 anelli. Il primo ciclo legge tutte le righe da file1e crea un hash, in %namescui ogni colonna che identifichiamo viene aggiunta.

$names{11AA} = 1;

Il secondo whileciclo viene quindi eseguito sul secondo file file2e la colonna 1 di ogni riga viene identificata utilizzando l'espressione regolare:

^(\S+).*

Quanto sopra dice dall'inizio della riga, abbina tutto ciò che non è uno spazio e salvalo nella variabile temporanea $1. Viene salvato avvolgendo le parentesi attorno ad esso. Il .*dice di abbinare tutto il resto sulla linea.

La prossima po 'di che le linee dice di guardare in alto nella colonna 1 bit che abbiamo appena salvato in $1nella %nameshash:

$names{$1}

Se è presente lì, non vogliamo stamparlo. Se non è presente, stampalo.


2

Metodo 1 # Bash

#!/usr/bin/env bash
file1=$1
file2=$2

[[ $# -ne 2 ]]  && { echo -e "\n\tUsage: \t$0 file1 file2\n"; exit 1; }

while read line
do

        if ! grep -q "${line%% .*}" $file1; then
                echo "${line}"
        fi

done < $file2

Metodo 2 # Solo Grep

grep -v "$(< file1)" file2

grep funziona, ma non garantisce


1

Prendiamolo come

File n. 1: file1.txt

File n. 2: file2.txt

Quindi eseguire il seguente terminale

fgrep -vf test1.txt test2.txt > output.txt

output.txt conterrà i risultati desiderati.

Spiegazione:

fgrep : print lines matching a pattern (from manual page)
-v  : get only non-matching rows
-f : obtain PATTERN from FILE (from manual page)

Funziona solo se intere linee sono identiche, ma l'interrogante ha chiesto esplicitamente il confronto solo sulla prima colonna.
Adaephon,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.