Chcę porównać plik1 z plikiem2 i wygenerować plik3, który zawiera wiersze w pliku1, których nie ma w pliku2.
Chcę porównać plik1 z plikiem2 i wygenerować plik3, który zawiera wiersze w pliku1, których nie ma w pliku2.
Odpowiedzi:
diff (1) nie jest odpowiedzią, ale comm (1) jest.
NAME
comm - compare two sorted files line by line
SYNOPSIS
comm [OPTION]... FILE1 FILE2
...
-1 suppress lines unique to FILE1
-2 suppress lines unique to FILE2
-3 suppress lines that appear in both files
Więc
comm -2 -3 file1 file2 > file3
Pliki wejściowe muszą zostać posortowane. Jeśli tak nie jest, najpierw je posortuj. Można to zrobić za pomocą pliku tymczasowego lub ...
comm -2 -3 <(sort file1) <(sort file2) > file3
pod warunkiem, że twoja powłoka obsługuje podstawianie procesów (bash tak).
comm -23
Narzędzie Unix diff
jest przeznaczone dokładnie do tego celu.
$ diff -u file1 file2 > file3
Więcej informacji na temat opcji, różnych formatów wyjściowych itp. Można znaleźć w instrukcji i w Internecie.
Rozważ to:
plik a.txt:
abcd
efgh
plik b.txt:
abcd
Możesz znaleźć różnicę w:
diff -a --suppress-common-lines -y a.txt b.txt
Wynik będzie:
efgh
Możesz przekreślić wynik w pliku wyjściowym (c.txt) za pomocą:
diff -a --suppress-common-lines -y a.txt b.txt > c.txt
To odpowie na twoje pytanie:
„... który zawiera linie w pliku1, których nie ma w pliku2”.
-d
, który postara się diff
znaleźć najmniejszą możliwą różnicę. -i
, -E
, -w
, -B
I --suppress-blank-empty
może być także przydatny czasami, choć nie zawsze. Jeśli nie wiesz, co pasuje do twojego przypadku użycia, spróbuj diff --help
najpierw (co jest ogólnie dobrym pomysłem, gdy nie wiesz, co może zrobić polecenie).
Czasami diff
jest to narzędzie, którego potrzebujesz, ale czasami join
jest bardziej odpowiednie. Pliki muszą być wstępnie posortowane lub, jeśli używasz powłoki obsługującej podstawianie procesów, takiej jak bash, ksh lub zsh, możesz sortować w locie.
join -v 1 <(sort file1) <(sort file2)
Próbować
sdiff file1 file2
Zwykle działa znacznie lepiej w większości przypadków. Możesz chcieć posortować pliki wcześniej, jeśli kolejność linii nie jest ważna (np. Niektóre tekstowe pliki konfiguracyjne).
Na przykład,
sdiff -w 185 file1.cfg file2.cfg
sdiff <(sort file1) <(sort file2)
Jeśli chcesz rozwiązać ten problem za pomocą coreutils, akceptowana odpowiedź jest dobra:
comm -23 <(sort file1) <(sort file2) > file3
Możesz także użyć sd (stream diff), który nie wymaga sortowania ani podstawiania procesów i obsługuje nieskończone strumienie, na przykład:
cat file1 | sd 'cat file2' > file3
Prawdopodobnie nie jest to duża korzyść w tym przykładzie, ale nadal rozważ to; w niektórych przypadkach nie będzie w stanie wykorzystać comm
ani grep -F
ani diff
.
Oto post na blogu, który napisałem o różnicowaniu strumieni na terminalu, który wprowadza sd.
Wiele odpowiedzi już jest, ale żadna z nich nie jest idealna IMHO. Odpowiedź Thanatosa pozostawia kilka dodatkowych znaków w linii, a odpowiedź Sorpigala wymaga sortowania lub wstępnego sortowania plików, co może nie być odpowiednie w każdych okolicznościach.
Myślę, że najlepszym sposobem na uzyskanie linii, które są różne i nic innego (bez dodatkowych znaków, bez ponownego zamawiania) jest kombinacją diff
, grep
i awk
(lub podobny).
Jeśli wiersze nie zawierają znaku „<”, krótką linijką może być:
diff urls.txt* | grep "<" | sed 's/< //g'
ale to usunie każde wystąpienie „<” (mniej niż, spacja) z linii, co nie zawsze jest OK (np. kod źródłowy). Najbezpieczniejszą opcją jest użycie awk:
diff urls.txt* | grep "<" | awk '{for (i=2; i<NF; i++) printf $i " "; print $NF}'
Ta jedna linijka porównuje oba pliki, następnie filtruje wyjście diff w stylu ed, a następnie usuwa końcowe „<”, które dodaje diff. Działa to nawet wtedy, gdy linie zawierają same „<”.
diff a1.txt a2.txt | grep '> ' | sed 's/> //' > a3.txt
Wypróbowałem prawie wszystkie odpowiedzi w tym wątku, ale żadna nie była kompletna. Po kilku szlakach powyżej jeden zadziałał. diff da ci różnicę, ale z pewnymi niechcianymi specjalnymi charasami. gdzie rzeczywiste linie różnicy zaczynają się od „>”. więc następnym krokiem jest grep linie zaczynające się od '>', po którym następuje usunięcie tego samego z sedem .
<
. Zobaczysz to, jeśli zmienisz kolejność plików wejściowych. Nawet jeśli to zrobiłeś, chciałbyś ominąć grep
używając więcej sed: `diff a1 a2 | sed '/> / s ///' 'Może to nadal przerywać linie zawierające >
lub <
w odpowiedniej sytuacji i nadal pozostawia dodatkowe linie opisujące numery linii. Jeśli chciał spróbować tego podejścia jest lepszym sposobem byłoby: diff -C0 a1 a2 | sed -ne '/^[+-] /s/^..//p'
.
Możesz użyć diff
z następującym formatowaniem wyjściowym:
diff --old-line-format='' --unchanged-line-format='' file1 file2
--old-line-format=''
, wyłącz wyjście dla plik1, jeśli linia różniła się od porównania w pliku2.
--unchanged-line-format=''
, wyłącz wyjście, jeśli linie są takie same.