2012-06-22 18 views
19

Ok, mam dwóch powiązanych list na moim Linuksie w plikach tekstowych:Bash - różnica między dwoma listami

/tmp/oldList 
/tmp/newList 

muszę porównać te listy, aby zobaczyć co zostało dodane linie i jakie linie dostałem usunięte. Muszę przetoczyć się przez te linie i wykonać na nich akcje w zależności od tego, czy zostały one dodane czy usunięte. Jak to zrobić w bash?

+0

To samo pytanie zostało zadane na 4 dni przed http://stackoverflow.com/questions/11099894/comparing-2-unsorted-lists-in-linux-listing-unique-in-the-second-file/11101143 # 11101143 –

Odpowiedz

50

użyć polecenia comm(1) porównać dwa pliki. Oba muszą być posortowane, co możesz zrobić wcześniej, jeśli są duże, lub możesz to zrobić w linii z bash podstawienie procesu.

comm może kombinacji flagi -1, -2 i -3 wskazujących który plik tłumienia linii z (unikalne dla pliku 1, unikalna dla pliku 2 lub wspólne dla obu).

Aby uzyskać linie tylko w starym pliku:

comm -23 <(sort /tmp/oldList) <(sort /tmp/newList) 

Aby uzyskać linie tylko w nowym pliku:

comm -13 <(sort /tmp/oldList) <(sort /tmp/newList) 

można karmić że w while read pętli przetwarzania każdą linię :

while read old ; do 
    ...do stuff with $old 
done < <(comm -23 <(sort /tmp/oldList) <(sort /tmp/newList)) 

i podobnie dla nowych linii.

4

Porówna się dla ciebie diff command.

np

$ diff /tmp/oldList /tmp/newList 

Patrz powyższy link do strony człowiek, aby uzyskać więcej informacji. To powinno zająć się twoją pierwszą częścią twojego problemu.

+1

Po prostu podkreślę, że polecenie 'diff' ma absurdalną liczbę opcji formatowania danych wyjściowych, które mogą stanowić wygodny wpis dla programu, który przetworzy różnice. – chepner

+0

@chepner dobry punkt .. zdecydowanie warto sprawdzić stronę z odnośnikiem. – Levon

0

Czy próbowałeś diff

$ diff /tmp/oldList /tmp/newList 

$ man diff 
2

Rozważ użycie Ruby, jeśli twoje skrypty wymagają czytelności.

Aby uzyskać linie tylko w starym pliku:

ruby -e "puts File.readlines('/tmp/oldList') - File.readlines('/tmp/newList')" 

Aby uzyskać linie tylko w nowym pliku:

ruby -e "puts File.readlines('/tmp/newList') - File.readlines('/tmp/oldList')" 

można karmić, że na chwilę czytać pętlę na przetwarzanie każdego linia:

while read old ; do 
    ...do stuff with $old 
done < ruby -e "puts File.readlines('/tmp/oldList') - File.readlines('/tmp/newList')" 
1

To jest stare, ale dla kompletności powinniśmy powiedzieć, że jeśli masz naprawdę duży zestaw, to t rozwiązaniem byłoby użycie diff do wygenerowania skryptu, a następnie zaopatrywać go w następujący sposób:

#!/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 

Linie zmieniły pojawi się jako usunięte i dodał. Jeśli ci się to nie podoba, możesz użyć --changed-group-format. Sprawdź stronę podręcznika zarządzania różnicami.

Powiązane problemy