it-swarm.com.de

Unterschied zwischen zwei Listen mit Bash

Ok, ich habe zwei zusammenhängende Listen auf meiner Linux-Box in Textdateien:

 /tmp/oldList
 /tmp/newList

Ich muss diese Listen vergleichen, um zu sehen, welche Zeilen hinzugefügt und welche Zeilen entfernt wurden. Ich muss dann diese Zeilen durchlaufen und Aktionen ausführen, je nachdem, ob sie hinzugefügt oder entfernt wurden.

Wie mache ich das in bash?

23
exvance

Verwenden Sie den Befehl comm(1), um die beiden Dateien zu vergleichen. Sie müssen beide sortiert werden, was Sie vorher tun können, wenn sie groß sind, oder Sie können dies inline mit bash process substituation tun.

comm kann aus einer Kombination der Flags -1, -2 und -3 bestehen, die angibt, aus welcher Datei Zeilen unterdrückt werden sollen (eindeutig für Datei 1, eindeutig für Datei 2 oder gemeinsam für beide).

So erhalten Sie die Zeilen nur in der alten Datei:

comm -23 <(sort /tmp/oldList) <(sort /tmp/newList)

So erhalten Sie die Zeilen nur in der neuen Datei:

comm -13 <(sort /tmp/oldList) <(sort /tmp/newList)

Sie können das in eine while read-Schleife einspeisen, um jede Zeile zu verarbeiten:

while read old ; do
    ...do stuff with $old
done < <(comm -23 <(sort /tmp/oldList) <(sort /tmp/newList))

und in ähnlicher Weise für die neuen Linien.

58
camh

Der Befehl diff führt den Vergleich für Sie durch.

z.B., 

$ diff /tmp/oldList /tmp/newList

Weitere Informationen finden Sie in der obigen Manpage. Dies sollte sich um den ersten Teil Ihres Problems kümmern.

5
Levon

Erwägen Sie die Verwendung von Ruby, wenn Ihre Skripte lesbar sind.

So erhalten Sie die Zeilen nur in der alten Datei:

Ruby -e "puts File.readlines('/tmp/oldList') - File.readlines('/tmp/newList')"

So erhalten Sie die Zeilen nur in der neuen Datei:

Ruby -e "puts File.readlines('/tmp/newList') - File.readlines('/tmp/oldList')"

Sie können das in eine while-Leseschleife einspeisen, um jede Zeile zu verarbeiten:

while read old ; do
  ...do stuff with $old
done < Ruby -e "puts File.readlines('/tmp/oldList') - File.readlines('/tmp/newList')"
3
Nowaker

Dies ist alt, aber der Vollständigkeit halber sollten wir sagen, dass, wenn Sie einen wirklich großen Satz haben, die schnellste Lösung die Verwendung von diff ist, um ein Skript zu generieren und es dann wie folgt zu erzeugen:

#!/bin/bash

line_added() {
   # code to be run for all lines added
   # $* is the line 
}

line_removed() {
   # code to be run for all lines removed
   # $* is the line 
}

line_same() {
   # code to be run for all lines at are the same
   # $* is the line 
}

cat /tmp/oldList | sort >/tmp/oldList.sorted
cat /tmp/newList | sort >/tmp/newList.sorted

diff >/tmp/diff_script.sh \
    --new-line-format="line_added %L" \
    --old-line-format="line_removed %L" \
    --unchanged-line-format="line_same %L" \
    /tmp/oldList.sorted /tmp/newList.sorted

source /tmp/diff_script.sh

Geänderte Zeilen werden als gelöscht und hinzugefügt angezeigt. Wenn Sie das nicht mögen, können Sie --changed-group-format verwenden. Überprüfen Sie die Diff-Handbuchseite.

1
Costa Tsaousis

Haben Sie versucht, diff

$ diff /tmp/oldList /tmp/newList

$ man diff
0
ssedano

Ich verwende normalerweise:

diff /tmp/oldList /tmp/newList | grep -v "Common subdirectories"

Die Option grep -v kehrt die Übereinstimmung um:

-v, --invert-match Ausgewählte Zeilen sind diejenigen, die keinem der angegebenen Muster entsprechen - Tern.

In diesem Fall werden also die diff-Ergebnisse verwendet und die üblichen Werte weggelassen.

0
Nathan