2009-03-06 12 views

risposta

302

Si potrebbe desiderare per guardare le applicazioni uniq e sort.

 
./yourscript.ksh | sort | uniq 

(A proposito, sì, il genere è necessario in questa riga di comando, uniq strisce solo linee duplicate che sono immediatamente dopo l'altro)

EDIT:

Contrariamente a quanto è stato pubblicato da Aaron Digulla in relazione alle opzioni della riga di comando uniq:

Dato il seguente input:

 
class 
jar 
jar 
jar 
bin 
bin 
java 

uniq uscita volontà tutte le linee esattamente una volta:

 
class 
jar 
bin 
java 

uniq -d uscita volontà tutte le linee che appaiono più di una volta, e li stamperà una volta:

 
jar 
bin 

uniq -u uscita volontà tutto linee che compaiono esattamente una volta e le stamperà una volta:

 
class 
java 
+1

Solo una FYI per i ritardatari: la risposta di @ AaronDigulla è stata successivamente corretta. – mklement0

+1

molto bene questo 'ordinamento è necessario in questa riga di comando, uniq si limita a separare le linee duplicate immediatamente dopo l'altra 'che ho appena appreso !! – HattrickNZ

+2

GNU 'sort' presenta una versione' -u' per dare anche i valori univoci. – Arthur2e5

9

Condurle tramite sort e uniq. Questo rimuove tutti i duplicati.

uniq -d fornisce solo i duplicati, uniq -u fornisce solo quelli univoci (strisce duplicati).

+0

devo prima ordinare l'aspetto di questo – Brabster

+1

Sì, lo fai. O più precisamente, è necessario raggruppare tutte le linee duplicate insieme. L'ordinamento lo fa però per definizione;) –

+0

Inoltre, 'uniq -u' NON è il comportamento predefinito (vedere la modifica nella mia risposta per i dettagli) –

9

Per i set di dati più grandi in cui l'ordinamento non può essere desiderabile, è anche possibile utilizzare il seguente script Perl:

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

Questo fondamentalmente solo ricorda ogni uscita di linea in modo che lo fa ancora una volta non è uscita.

Ha il vantaggio rispetto alla soluzione "sort | uniq" in quanto non è necessario alcun ordinamento in anticipo.

+2

Si noti che l'ordinamento di un file molto grande non è un problema di per sé con ordinamento; può ordinare file che sono più grandi della RAM + swap disponibile. Perl, OTOH, fallirà se ci sono solo pochi duplicati. –

+0

Sì, è un compromesso a seconda dei dati previsti. Perl è migliore per un enorme set di dati con molti duplicati (non è richiesto lo storage basato su disco). Un enorme set di dati con pochi duplicati dovrebbe usare sort (e archiviazione su disco). Piccoli set di dati possono usare entrambi. Personalmente, proverei prima Perl, cambio per ordinare se fallisce. – paxdiablo

+0

Poiché sort offre un vantaggio solo se deve passare al disco. – paxdiablo

9

Con zsh si può fare questo:

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 

Oppure si può utilizzare AWK:

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

Soluzioni intelligenti che non prevedono l'ordinamento dell'input. Avvertenze: La soluzione 'awk' molto intelligente ma criptica (vedere http://stackoverflow.com/a/21200722/45375 per una spiegazione) funzionerà con file di grandi dimensioni finché il numero di linee univoche è piccolo abbastanza (come vengono conservate in memoria righe univoche). La soluzione 'zsh' legge prima l'intero file in memoria, che potrebbe non essere un'opzione con file di grandi dimensioni. Inoltre, come scritto, solo le linee senza spazi incorporati sono gestite correttamente; per risolvere questo problema, usa 'IFS = $ '\ n' leggi -d '' -r -A u mklement0

+0

corretto. Oppure: '(IFS = $ '\ n' u = ($ (

+1

Grazie, è più semplice (supponendo che non sia necessario per impostare le variabili necessarie al di fuori della subshell). Sono curioso di sapere quando hai bisogno del suffisso '[@]' per fare riferimento a tutti gli elementi di un array - sembra che - almeno a partire dalla versione 5 - funzioni senza di esso; o l'hai appena aggiunto per chiarezza? – mklement0

59
./script.sh | sort -u 

Questo è lo stesso monoxide'sanswer, ma un po 'più conciso.

+4

Stai modesto: la tua soluzione sarà anche migliore (probabilmente solo notevole con grandi set di dati). – mklement0

1

Unico, come richiesto (ma non ordinato);
utilizza meno risorse di sistema per meno di ~ 70 elementi (come testato con il tempo);
scritto di prendere input da stdin,
(o modificare e inserire in un altro script):
(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

Con AWK si può fare, lo trovo più veloce di sorta

./yourscript.ksh | awk '!a[$0]++' 
Problemi correlati