Vergleichen Sie zwei Dateien mit der ersten Spalte und entfernen Sie doppelte Zeilen aus der zweiten Datei im Shell-Skript

9

Ich werde meine Frage anhand eines Beispiels stellen. Ich habe 2 Dateien:

Datei 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

Datei 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

Gewünschte Ausgabe

Datei 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

Ich möchte Datei 1 und Datei 2 anhand ihrer ersten Spalten vergleichen und die gesamte Zeile oder Zeile aus Datei 2 entfernen, wo sie in Datei 1 übereinstimmen. Ich möchte die Ergebnisse auch in einer dritten Datei, Datei 3, speichern.

Rahul Rana
quelle

Antworten:

10

Sie können dafür verwenden awk:

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

Erläuterung:

  • FNR == NR: Dieser Test ist wahr, wenn die Anzahl der Datensätze der Anzahl der Datensätze in der Datei entspricht. Dies gilt nur für die erste Datei, da die zweite Datei NRder Anzahl der Zeilen von Datei1 + entspricht FNR.

  • a[$1]: Erstellen Sie einen Array-Elementindex für das erste Feld von Datei1.

  • next: Fahren Sie mit dem nächsten Datensatz fort, damit Datei1 nicht mehr verarbeitet wird.

  • !($1 in a): Überprüfen Sie, ob das erste Feld ($ 1) im Array vorhanden ist, dh in Datei1, und drucken Sie die gesamte Zeile (in Datei3).

Basierend auf einem der Beispiele aus dem #awk Wiki .

Jasonwryan
quelle
Perfekte Antwort!!!
MTK
8
export LC_ALL=C
comm -13 <(sort f1) <(sort  f2)

Würde die Zeilen melden, die nur in sind f2.

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

Würde die Zeilen melden, f2deren erstes Feld nicht als erstes Feld in einer Zeile von gefunden wird f1.

(Sie brauchen eine Schale mit Unterstützung für die Prozess- Substitution wie ksh93, zshoder bash).

Stéphane Chazelas
quelle
2

Nur zum Spaß hier eine Lösung 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};
}

Beispiel

$ ./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

Einzelheiten

Die obige Perl-Lösung besteht aus 2 Schleifen. Die erste Schleife liest alle Zeilen von ein file1und erstellt einen Hash, %namesin den jede von uns identifizierte Spalte eingefügt wird.

$names{11AA} = 1;

Die 2. whileSchleife läuft dann über die 2. Datei, file2und die Spalte 1 jeder Zeile wird mit dem regulären Ausdruck identifiziert:

^(\S+).*

Das Obige sagt vom Anfang der Zeile an, stimmen Sie mit allem überein, was kein Leerzeichen ist, und speichern Sie es in der temporären Variablen $1. Es wird gerettet, indem man Parens darum wickelt. Das .*sagt, um alles andere auf der Linie zusammenzubringen.

Das nächste Bit dieser Zeile besagt, dass das Bit der Spalte 1 nachgeschlagen werden soll, das wir gerade $1im %namesHash gespeichert haben :

$names{$1}

Wenn es dort vorhanden ist, möchten wir es nicht drucken. Wenn es nicht vorhanden ist, drucken Sie es aus.

slm
quelle
2

Methode 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

Methode 2 # Nur Grep

grep -v "$(< file1)" file2

grep funktioniert, aber keine Garantie

Rahul Patil
quelle
1

Lass es uns so verstehen

Datei 1: file1.txt

Datei 2: file2.txt

Führen Sie dann die folgenden Schritte auf dem Terminal aus

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

output.txt enthält die gewünschten Ergebnisse.

Erläuterung:

fgrep : print lines matching a pattern (from manual page)
-v  : get only non-matching rows
-f : obtain PATTERN from FILE (from manual page)
inckka
quelle
Dies funktioniert nur, wenn ganze Zeilen identisch sind, der Fragesteller jedoch nur in der ersten Spalte ausdrücklich zum Vergleich aufgefordert wird.
Adaephon