2009-03-06 3 views

Antwort

302

Vielleicht möchten um die uniq und sort Anwendungen zu betrachten.

 
./yourscript.ksh | sort | uniq 

(FYI, ja, die Art ist in dieser Befehlszeile erforderlich, uniq Streifen nur doppelte Zeilen, die unmittelbar nach einander sind)

EDIT:

Im Gegensatz zu dem, was gewesen ist geschrieben von Aaron Digulla in Bezug auf uniq 's Kommandozeilenoptionen:

Gegeben die folgenden Eingabe:

 
class 
jar 
jar 
jar 
bin 
bin 
java 

uniq gibt alle Zeilen genau einmal:

 
class 
jar 
bin 
java 

uniq -d gibt alle Zeilen, die mehr als einmal erscheinen, und es wird sie einmal drucken:

 
jar 
bin 

uniq -u gibt alle Zeilen, die genau einmal angezeigt werden, und es wird einmal gedruckt:

 
class 
java 
+1

Nur ein Vorgeschmack auf Nachzügler: @ AaronDigulla's Antwort wurde seither korrigiert. – mklement0

+1

sehr gut Punkt diese Art ist in dieser Befehlszeile notwendig, Uniq nur Streifen doppelte Zeilen, die unmittelbar nacheinander sind, die ich gerade gelernt habe !! – HattrickNZ

+2

GNU 'sort' hat eine' -u' Version, um auch die einzigartigen Werte zu geben. – Arthur2e5

9

Pipe sie durch sort und uniq. Dies entfernt alle Duplikate.

uniq -d gibt nur die Duplikate, uniq -u gibt nur die Einzigen (Streifen Duplikate).

+0

muss zuerst nach dem Aussehen sortieren – Brabster

+1

Ja, das tust du. Oder genauer gesagt müssen Sie alle doppelten Zeilen zusammenfassen. Das Sortieren tut dies definitionsgemäß;) –

+0

Außerdem ist 'uniq -u' NICHT das Standardverhalten (siehe die Bearbeitung in meiner Antwort für Details). –

9

Für größere Datenmengen, wo möglicherweise nicht wünschenswert sein, sortieren, können Sie auch folgende Perl-Skript verwenden:

./yourscript.ksh | perl -ne 'if (!defined $x{$_}) { print $_; $x{$_} = 1; }' 

Diese im Grunde nur jede Zeile ausgegeben, erinnert sich, so dass es nicht ausgegeben hat es wieder.

Es hat den Vorteil gegenüber der "sort | uniq" -Lösung, dass im Vorfeld keine Sortierung erforderlich ist.

+2

Beachten Sie, dass das Sortieren einer sehr großen Datei per se kein Problem darstellt. Es kann Dateien sortieren, die größer sind als der verfügbare RAM + Swap. Perl, OTOH, wird fehlschlagen, wenn nur wenige Duplikate vorhanden sind. –

+0

Ja, es ist ein Kompromiss abhängig von den erwarteten Daten. Perl ist besser für große Datasets mit vielen Duplikaten (kein Festplattenspeicher erforderlich). Ein großer Datensatz mit wenigen Duplikaten sollte sort (und disk storage) verwenden. Kleine Datasets können beides verwenden. Persönlich würde ich zuerst Perl ausprobieren, um zu sortieren, wenn es fehlschlägt. – paxdiablo

+0

Da sort nur einen Vorteil bringt, wenn es auf die Festplatte wechseln muss. – paxdiablo

9

Mit zsh Sie dies tun können:

zsh-5.0.0[t]% cat infile 
tar 
more than one word 
gz 
java 
gz 
java 
tar 
class 
class 
zsh-5.0.0[t]% print -l "${(fu)$(<infile)}" 
tar 
more than one word 
gz 
java 
class 

Oder Sie verwenden AWK:

zsh-4.3.9[t]% awk '!_[$0]++' infile  
tar 
more than one word 
gz 
java 
class 
+2

Clevere Lösungen, bei denen die Eingabe nicht sortiert wird. Vorbehalte: Die sehr clevere aber kryptische 'awk'-Lösung (siehe http://stackoverflow.com/a/21200722/45375 für eine Erklärung) funktioniert mit großen Dateien, solange die Anzahl der eindeutigen Zeilen gering ist genug (als eindeutige Zeilen werden im Speicher gehalten). Die 'zsh'-Lösung liest zuerst die gesamte Datei in den Speicher, was bei großen Dateien nicht möglich ist. Wie geschrieben, werden nur Zeilen ohne eingebettete Leerzeichen korrekt behandelt. Um dies zu beheben, verwenden Sie 'IFS = $ '\ n' read -d '' -r -A mklement0

+0

Korrigieren. Oder: '(IFS = $ '\ n' u = ($ (

+1

Danke, das ist einfacher (vorausgesetzt, du brauchst es nicht um Variablen außerhalb der Subshell zu setzen). Ich bin neugierig, wenn Sie das Suffix '[@]' benötigen, um alle Elemente eines Arrays zu referenzieren - scheint, dass - zumindest ab Version 5 - es ohne es funktioniert; oder hast du es nur für die Klarheit hinzugefügt? – mklement0

59
./script.sh | sort -u 

Dies ist die gleiche wie monoxide'sanswer, aber ein bisschen mehr prägnant.

+4

Sie sind bescheiden: Ihre Lösung wird auch _perform_ besser (wahrscheinlich nur bei großen Datensätzen). – mklement0

1

Einmalig, wie gewünscht, (aber nicht sortiert);
verwendet weniger Systemressourcen für weniger als ~ 70 Elemente (wie mit der Zeit getestet);
geschrieben Eingang nehmen von stdin,
(oder zu ändern, und dies in einem anderen Skript):
(Bash)

bag2set() { 
    # Reduce a_bag to a_set. 
    local -i i j n=${#a_bag[@]} 
    for ((i=0; i < n; i++)); do 
     if [[ -n ${a_bag[i]} ]]; then 
      a_set[i]=${a_bag[i]} 
      a_bag[i]=$'\0' 
      for ((j=i+1; j < n; j++)); do 
       [[ ${a_set[i]} == ${a_bag[j]} ]] && a_bag[j]=$'\0' 
      done 
     fi 
    done 
} 
declare -a a_bag=() a_set=() 
stdin="$(</dev/stdin)" 
declare -i i=0 
for e in $stdin; do 
    a_bag[i]=$e 
    i=$i+1 
done 
bag2set 
echo "${a_set[@]}" 
2

Mit AWK Sie tun können, finde ich es schneller als Art

./yourscript.ksh | awk '!a[$0]++' 
Verwandte Themen