Jestem pewien, że kiedyś znalazłem polecenie uniksowe, które może drukować wspólne linie z dwóch lub więcej plików, czy ktoś zna jego nazwę? To było o wiele prostsze niż diff
.
unix
shell
command-line
za dużo php
źródło
źródło
comm
wymagają posortowanych plików wejściowych. Jeśli chcesz korzystać tylko z linii po linii, to świetnie. Ale jeśli chcesz czegoś, co nazwałbym „anti-diff”,comm
to nie działa.pr-123-xy-45
plik2ec11_orop_pr-123-xy-45.gz
. Potrzebuję plik3 zawierającyec11_orop_pr-123-xy-45.gz
Odpowiedzi:
Polecenie, którego szukasz, to
comm
. na przykład:-Tutaj:
-1 : pomija kolumnę 1 (wiersze unikalne dla 1.sorted.txt)
-2 : pomija kolumnę 2 (wiersze unikalne dla 2.sorted.txt)
źródło
grep
robi dziwne rzeczy, których możesz się nie spodziewać. W szczególności wszystko w1.txt
będzie interpretowane jako wyrażenie regularne, a nie zwykły ciąg. Również każda pusta linia w1.txt
dopasuje wszystkie linie w2.txt
. Więcgrep
będzie działać tylko w bardzo specyficznych sytuacjach. Przynajmniej chcesz użyćfgrep
(lubgrep -f
), ale ta pusta linia prawdopodobnie spowoduje spustoszenie w tym procesie.grep -F -x -f file1 file2
.comm
polecenia w 3 osobnych plikach? Odpowiedź była o wiele za duża, by zmieścić się tutaj wygodnie.Aby łatwo zastosować polecenie comm do nieposortowanych plików, użyj podstawienia procesu Basha :
Zatem pliki abc i def mają jedną wspólną linię, tę z „132”. Korzystanie z comm na nieposortowanych plikach:
Ostatni wiersz nie dał żadnych wyników, wspólny wiersz nie został wykryty.
Teraz użyj comm na posortowanych plikach, sortując pliki z podstawieniem procesu:
Teraz mamy linię 132!
źródło
sort abc > abc.sorted
,sort dev > def.sorted
a potemcomm -12 abc.sorted def.sorted
?Aby uzupełnić jednowarstwową wersję Perla, oto jej
awk
odpowiednik:Spowoduje to odczytanie wszystkich wierszy z
file1
tablicyarr[]
, a następnie sprawdzenie każdej linii,file2
jeśli już istnieje w tablicy (tjfile1
.). Znalezione wiersze zostaną wydrukowane w kolejności, w jakiej występująfile2
. Zauważ, że porównaniein arr
używa całej linii odfile2
indeksu do tablicy, więc będzie raportować tylko dokładne dopasowania dla całych linii.źródło
perl
tych, ponieważ). Dzięki milionie, PaniMoże masz na myśli
comm
?Sekretem w znalezieniu tych informacji są strony informacyjne. W przypadku programów GNU są one znacznie bardziej szczegółowe niż ich strony podręcznika. Spróbuj,
info coreutils
a wyświetli się lista wszystkich małych przydatnych narzędzi.źródło
Podczas
daje różnice między dwoma plikami (co jest w 2.txt, a nie w 1.txt), możesz łatwo zrobić
zebrać wszystkie typowe wiersze, które powinny zapewnić łatwe rozwiązanie problemu. Jeśli jednak posortowałeś pliki, powinieneś je wziąć
comm
. Pozdrowienia!źródło
grep
robi dziwne rzeczy, których nie możesz się spodziewać. W szczególności wszystko w1.txt
będzie interpretowane jako wyrażenie regularne, a nie zwykły ciąg. Również każda pusta linia w1.txt
dopasuje wszystkie linie w2.txt
. Będzie to działać tylko w bardzo specyficznych sytuacjach.grep
notacji POSIX , które są obsługiwane przezgrep
znalezione w większości współczesnych wariantów Uniksa. Dodaj-F
(lub użyjfgrep
), aby ukryć wyrażenia regularne. Dodaj-x
(dokładnie), aby dopasować tylko całe linie.comm
za posortowane pliki?comm
może pracować z dowolnie dużymi plikami, o ile są one posortowane, ponieważ zawsze muszą przechowywać tylko trzy linie w pamięci (domyślam się,comm
że GNU wiedziałby nawet, aby zachować tylko prefiks, jeśli linie są naprawdę długie).grep
Rozwiązanie wymaga, aby wszystkie wyrażenia wyszukiwania w pamięci.Jeśli dwa pliki nie są jeszcze posortowane, możesz użyć:
i to będzie działać, unikając komunikatu o błędzie
comm: file 2 is not in sorted order
, gdy robicomm -12 a.txt b.txt
.źródło
<(command)
nie jest przenośna dla powłoki POSIX, chociaż działa w Bash i niektórych innych.źródło
comm
polecenia, gdyż przeszukuje każdy wierszfile1
wfile2
którymcomm
będzie porównać tylko jeśli linian
wfile1
jest równa liniin
wfile2
.comm
nie porównuje po prostu linii N w pliku 1 z linią N w pliku 2. Może doskonale zarządzać serią linii wstawionych do dowolnego pliku (co oczywiście jest równoznaczne z usunięciem serii linii z drugiego pliku). Wymaga jedynie posortowania danych wejściowych.comm
odpowiedzi, jeśli chce się zachować porządek. Lepsze niżawk
odpowiedź, jeśli nie chce się duplikatów.źródło
W ograniczonej wersji Linuksa (jak QNAP (nas), nad którą pracowałem):
grep -f file1 file2
może powodować pewne problemy, jak powiedział @ChristopherSchultz, a używaniegrep -F -f file1 file2
było naprawdę powolne (ponad 5 minut - nie skończyłem - ponad 2-3 sekundy z poniższą metodą na plikach powyżej 20 MB)Oto co zrobiłem:
Jeśli
files.same.sorted
powinny być w tej samej kolejności niż oryginalne, dodaj ten wiersz dla tego samego zamówienia niż plik 1:lub, dla tego samego zamówienia, co plik 2:
źródło
Tylko w celach informacyjnych, jeśli ktoś nadal zastanawia się, jak to zrobić dla wielu plików, zobacz połączoną odpowiedź na temat Znajdowanie pasujących wierszy w wielu plikach.
Łącząc te dwie odpowiedzi ( ans1 i ans2 ), myślę, że możesz uzyskać wynik, którego potrzebujesz, bez sortowania plików:
Wystarczy go zapisać, nadać mu uprawnienia do wykonywania (
chmod +x compareFiles.sh
) i uruchomić. Spowoduje to pobranie wszystkich plików znajdujących się w bieżącym katalogu roboczym i wykonanie porównania „wszystko przeciwko wszystkim”, pozostawiając wynik w pliku „dopasowywanie_ linii”.Rzeczy do poprawy:
źródło
To powinno to zrobić.
źródło
rm -f file3.txt
jeśli chcesz usunąć plik; nie zgłosi żadnego błędu, jeśli plik nie istnieje. OTOH, nie byłoby konieczne, aby twój skrypt po prostu odbijał się echem od standardowego wyjścia, pozwalając użytkownikowi skryptu wybrać, dokąd dane wyjściowe powinny się udać. Ostatecznie prawdopodobnie będziesz chciał użyć$1
i$2
(argumenty wiersza poleceń) zamiast ustalonych nazw plików (file1.out
ifile2.out
). Pozostawia to algorytm: będzie on powolny. Przeczytafile2.out
raz dla każdej liniifile1.out
. Będzie dużo, jeśli pliki będą duże (powiedzmy kilka kilobajtów).grep -F
które odczytuje jeden plik do pamięci, a następnie wykonuje jedno przejście przez drugi, pozwala uniknąć powtarzania się obu plików wejściowych.