2012-04-26 8 views
9

Prawdopodobnie jest to bardzo podstawowe pytanie dla programistów powłoki. Załóżmy jednak, że mam plik tekstowy A i B , a B to podzestaw A.podstawowe programowanie powłoki

Chcę utworzyć plik tekstowy C zawierający dane (A-B).

Pomiń wszystkie wspólne linie.

Linia w plikach są dane numeryczne: jak

id , some aspect, other aspec. 

Dzięki.

+0

Nie wspomniano, czy inaczej, czy Twoje dane mogą zawierać powtarzające się linie. Jeśli to możliwe, należy pamiętać, że metoda "sort" + 'uniq' firmy Tim Pote ** nie działa **, gdy w" A "występują niedopasowane zduplikowane linie. Metody 'awk' i' comm' działają z duplikatami w 'A'. –

Odpowiedz

12

Zastosowanie sort i uniq

sort a b | uniq -u 

Jeśli chcesz wiersze, które są takie same między A i B, można użyć uniq -d

sort a b | uniq -d 

Zakłada to oczywiście, że dane w A i B są dokładnie takie same jak . W zestawach danych nie można utracić spacji ani kart. Jeśli tak, musisz najpierw wyczyścić dane przy pomocy sed, tr lub lub .

Edit

Peter. O podkreślił, to nie powiedzie się, jeśli zdarzają się dokładne duplikaty w pliku a. Jeśli to problem, można go naprawić w ten sposób:

sort <(sort -u a) b | uniq -u 
+0

bardzo naiwne pytanie. Jak zapisać go w pliku "c"? – Fraz

+1

Musisz przekierować wyjście za pomocą '>'.Tak więc polecenie brzmiałoby: 'sort a b | uniq -u> c' –

+1

'posortuj b | uniq -u> c' – dpp

4

Jednym ze sposobów korzystania awk. Przekieruj, aby zapisać zawartość w dowolnym pliku zamiast STDOUT.

awk 'FNR == NR { data[ $0 ] = 1; next } FNR < NR { if ($0 in data) { next } print $0 }' fileB fileA 

AKTUALIZACJA z bardziej efektywnego polecenia. Dzięki Peter.O:

awk 'FNR==NR{data[$0]; next}; $0 in data{next}; 1' fileB fileA 
+0

Zaledwie kilka punktów, które sprawiają, że jest nieco bardziej spójny (i szybszy): 1) Nie musisz przypisywać wartości do tablicy; właśnie odnosząc się do niego tworzy część indeksu. 2) Drugi test FNR nie jest potrzebny, ponieważ poprzedzające go "następne" jest odpowiednie. 3) Test "if" jest zbędny, ponieważ '$ 0 in data' jest testem sam w sobie. 4) Każda niezerowa wartość spowoduje wydrukowanie '0 $', więc' print $ 0' może być "wartością logiczną": 'awk 'FNR == NR {data [$ 0]; Kolejny}; 0 USD w danych {next}; 1 'fileB fileA' –

+0

@ Peter.O: Dziękuję za sugestie. Dodaję twoje polecenie do odpowiedzi. – Birei

+0

Nie potrzebujesz także tych pustych instrukcji (kończąc średnikami), a zamiast testować za 0 USD w danych i robiąc następne, a potem masz niejawny wydruk, możesz po prostu zanegować test i nie potrzebujesz pierwszej dalej (chyba że plik B jest ogromny, a wydajność to problem), więc możesz po prostu napisać to jako 'awk 'FNR == NR {data [$ 0]}! (0 USD w danych)' plik B plikA." –

7

Istnieje narzędzie o nazwie comm, który jest używany do właśnie tego:

comm -23 A B > C 

gdzie -2 oznacza „odrzucić linii unikalnych złożyć B” (można powiedzieć tam aren any), a -3 oznacza "odrzucić linie wspólne dla obu plików".

@BartonChittenden sprawia, że ​​dobry punkt:

comm -23 <(sort A) <(sort B) > C 
+2

Pamiętaj, że oba pliki muszą być –

+0

+1 za pokazanie mi 'comm', o którym nigdy nie słyszałem. +10 do pokazywania mi' <(command) ', którego nigdy nie słyszałem. –

+1

To się nazywa" proces substytucji "i pozwala leczyć wyjście komendy, tak jakby była plikiem, zobacz stronę podręcznika. –

2
awk 'FNR==NR{a[$0];next}(!($0 in a))' B A