Czy jest jakieś narzędzie, które może uzyskać linie, które zawiera plik A, ale plik B nie? Mógłbym napisać prosty skrypt z np. Perlem, ale jeśli coś takiego już istnieje, od tej pory oszczędzę czas.
Czy jest jakieś narzędzie, które może uzyskać linie, które zawiera plik A, ale plik B nie? Mógłbym napisać prosty skrypt z np. Perlem, ale jeśli coś takiego już istnieje, od tej pory oszczędzę czas.
Odpowiedzi:
Tak. Za pomocą standardowego grep
narzędzia do wyszukiwania plików w poszukiwaniu ciągów tekstowych można odjąć wszystkie wiersze jednego pliku od drugiego.
grep -F -x -v -f fileB fileA
Działa to poprzez użycie każdej linii w pliku B jako wzorca ( -f fileB
) i traktowanie go jako zwykłego ciągu pasującego do siebie (nie zwykłego wyrażenia regularnego) ( -F
). Zmuszasz dopasowanie do całej linii ( -x
) i wypisujesz tylko te linie, które nie pasują ( -v
). Dlatego drukujesz linie w pliku A, które nie zawierają tych samych danych, co dowolna linia w pliku B.
Minusem tego rozwiązania jest to, że nie bierze ono pod uwagę kolejności linii, a jeśli dane wejściowe mają zduplikowane linie w różnych miejscach, możesz nie otrzymać tego, czego oczekujesz. Rozwiązaniem tego jest użycie prawdziwego narzędzia porównywania, takiego jak diff
. Możesz to zrobić, tworząc plik różnicowy o wartości kontekstu na 100% linii w pliku, a następnie analizując go pod kątem tylko linii, które zostałyby usunięte w przypadku konwersji pliku A do pliku B. (Uwaga: to polecenie usuwa również różnicę formatowanie po uzyskaniu właściwych wierszy).
diff -U $(wc -l < fileA) fileA fileB | sed -n 's/^-//p' > fileC
-u
faktycznie zajmuje parametr liczby, o ile nie następuje po nim spacja. Zaletą tego, co miałem wcześniej, jest to, że będzie działać z wartością lub bez, więc możesz użyć czegoś w tej procedurze podrzędnej, która nie zwraca danych wyjściowych. Z drugiej strony wielkie litery „-U” wymagają argumentu.
diff
rurociąg działa wspaniale dzięki.
grep
potrzebą. Przykład:grep -F -x -v -f <(sort fileB) <(sort fileA)
diff
jest to, że pozycja w pliku jest brana pod uwagę.
Odpowiedź zależy w dużej mierze od rodzaju i formatu porównywanych plików.
Jeśli porównywane pliki są posortowanymi plikami tekstowymi, narzędzie GNU napisane przez Richarda Stallmana i Davide McKenzie comm
może wywołać filtrowanie, którego szukasz. Jest częścią coreutils.
Załóżmy, że masz 2 następujące pliki:
$ cat a
1
2
3
4
5
$ cat b
1
2
3
4
5
6
Linie w pliku b
, których nie ma w pliku a
:
$ comm <(sort a) <(sort b) -3
6
comm
; niestety comm
wymaga posortowanych plików
<()
? Działa i rozumiem, ale czy istnieje nazwa tej dziwności?
<()
jest również znany jako podstawienie procesu .
comm
został pierwotnie napisany około 1973 roku przez kogoś z Bell Labs, a nie rms. Mówisz o implementacji GNU, która pojawiła się dużo później. Przez lata istniało wiele różnych implementacji narzędzi uniksowych.
z przepełnienia stosu ...
comm -23 plik1 plik2
-23 pomija wiersze znajdujące się w obu plikach lub tylko w pliku 2. Pliki muszą zostać posortowane (są one w twoim przykładzie), ale jeśli nie, najpierw przeprowadź je przez sortowanie ...
Zobacz stronę podręcznika tutaj
Metody grep i comm (z sortowaniem) zajmują dużo czasu w przypadku dużych plików. SiegeX i ghostdog74 udostępniają dwie świetne metody awk do wyodrębniania linii unikatowych dla jednego z dwóch plików w przepełnieniu stosu:
$ awk 'FNR==NR{a[$0]++}FNR!=NR && !a[$0]{print}' file1 file2
$ awk 'FNR==NR{a[$0]++;next}(!($0 in a))' file1 file2
Jeśli pliki są duże i nie masz niestandardowego porządku dla swoich wpisów, grep trwa o wiele za długo. Szybka alternatywa byłaby
sort file1 > 1
sort file2 > 2
diff 1 2 | grep "\>" | sed -e 's/> //'
[plik2-plik1 wyniki do ekranu, potok do pliku itp.]
Zmiana >
na <
uzyskałaby przeciwne odjęcie.rm 1 2