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?
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.
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.
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')"
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.
Haben Sie versucht, diff
$ diff /tmp/oldList /tmp/newList
$ man diff
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.