2009-03-13 14 views
6

Aby użyć polecenia uniq, należy najpierw posortować plik.Jak zachować format pliku, jeśli używasz polecenia uniq (w powłoce)?

Ale w pliku, który mam, kolejność informacji jest ważna, więc w jaki sposób mogę zachować oryginalny format pliku, ale nadal pozbyć się zduplikowanej zawartości?

+0

Chcesz zachować tylko pierwsze wystąpienie wzoru? A może tylko ostatni? Musisz być trochę bardziej konkretny niż ten ... – wzzrd

+0

Plik jest podobny do tego. wzorzec1 pattern2 pattern3 pattern4 wzorzec1 pattern2 etc ... wzorzec1 różni się od pattern2, i tak dalej. Np.) Wzorzec 1 to tytuł, a wzorzec 2 to numer telefonu. Jeśli posortuję plik, numery telefonów nie będą pod właściwym tytułem itp. – Dennis

+0

Zapomniałem tej sekcji komentarza, która nie zachowuje formatu. Tak więc ten post może być nieco trudny do zrozumienia. – Dennis

Odpowiedz

10

Inna wersja awk:

awk '!_[$0]++' infile 
+0

O (n) rozwiązanie w 8 bajtach. +1 – ashawley

+0

haha, słodkie! jak to działa? (+1) –

+0

ah, teraz widzę :) –

0

Można użyć jakiś straszny O (n^2) sprawa, jak ten (pseudo-kod):

file2 = EMPTY_FILE 
for each line in file1: 
    if not line in file2: 
    file2.append(line) 

Jest to potencjalnie dość powolny, zwłaszcza jeśli zostaną zrealizowane na poziomie bash. Ale jeśli twoje pliki są względnie krótkie, prawdopodobnie będą działać poprawnie i będą szybkie do wdrożenia (not line in file2 to tylko grep -v itd.).

W przeciwnym razie można zakodować specjalny program, używając bardziej zaawansowanej struktury danych w pamięci, aby przyspieszyć pracę.

+0

Dzięki odprężeniu. Plik, który mam teraz, jest tylko przykładowym plikiem, więc jest raczej krótki. Ale pliki, których będę używał, będą duże. Zobaczę, co sugerują inni, a na razie prawdopodobnie wypróbuję Twoją sugestię. – Dennis

1

można uruchomić uniq -d na posortowanej wersji pliku, aby znaleźć duplikaty wierszy, a następnie uruchomić jakiś skrypt, który mówi:

if this_line is in duplicate_lines { 
    if not i_have_seen[this_line] { 
     output this_line 
     i_have_seen[this_line] = true 
    } 
} else { 
    output this_line 
} 
+0

Zaletą tego rozwiązania, w przeciwieństwie do nieco prostszych rozwiązań, jest to, że nie zachowuje się mapowania każdej linii w pliku, a jedynie duplikaty linii. – chaos

+0

oh poczekaj. nie myślałem o -d. głupi litb. no cóż, przecież można go przeciąć na korzyść :) –

+0

wydanie końcowe po wpisaniu w -d zamiast użyć kom: sort file.txt | uniq -d | awk 'FNR == NR {dups [$ 0]; } FNR! = NR {if ($ 0 w dups) {if (! (0 $ w liniach)) {print $ 0; linie [0 USD]; }} else wydrukuj $ 0; } '- file.txt –

4

Ten awk utrzymuje pierwsze wystąpienie. Sam algorytm jak innych odpowiedzi użyć:

awk '!($0 in lines) { print $0; lines[$0]; }' 

Oto jeden, który potrzebuje tylko do przechowywania zduplikowanych wierszy (w przeciwieństwie do wszystkich liniach) za pomocą awk:

sort file | uniq -d | awk ' 
    FNR == NR { dups[$0] } 
    FNR != NR && (!($0 in dups) || !lines[$0]++) 
' - file 
0
for line in $(sort file1 | uniq); do 
    grep -n -m1 line file >>out 
done; 

sort -n out 

najpierw zrobić coś w rodzaju,

dla każdej unikalnej wartości grep dla pierwszego dopasowania (-m1)

i zachowaj numery linii

sortuj dane wyjściowe numerycznie (-n) według numeru linii.

można następnie usunąć wiersz # 'sz sed lub awk

4

Jest także «linia numer dwukrotnie sort» metoda.

nl -n ln | sort -u -k 2| sort -k 1n | cut -f 2- 
+0

+1 dla rozwiązania, które działa z bardzo dużymi plikami. Ale czy nie powinno to być "sort -k 1n" (sortowanie numeryczne)? –

+0

tak, masz rację. – ashawley

1

Używając tylko Uniq i grep:

Tworzenie d.sh:

#!/bin/sh 
sort $1 | uniq > $1_uniq 
for line in $(cat $1); do 
cat $1_uniq | grep -m1 $line >> $1_out 
cat $1_uniq | grep -v $line > $1_uniq2 
mv $1_uniq2 $1_uniq 
done; 
rm $1_uniq 

Przykład:

./d.sh infile 
Powiązane problemy