2009-03-06 20 views

Respuesta

302

Es posible que desee para mirar las aplicaciones uniq y sort.

 
./yourscript.ksh | sort | uniq 

(FYI, sí, el tipo es necesaria en esta línea de comandos, uniq solamente tiras líneas duplicadas que son inmediatamente después de la otra)

EDIT:

Contrariamente a lo que ha sido publicado por Aaron Digulla en relación con las opciones de línea de comandos uniq:

Con la siguiente entrada:

 
class 
jar 
jar 
jar 
bin 
bin 
java 

uniq es la salida de todas las líneas exactamente una vez:

 
class 
jar 
bin 
java 

uniq -d es la salida de todas las líneas que aparecen más de una vez, y se imprimirá una vez:

 
jar 
bin 

uniq -u da salida a todos líneas que aparecen exactamente una vez, y las imprimirá una vez:

 
class 
java 
+1

Solo un FYI para los que llegan tarde: la respuesta de @ AaronDigulla ha sido corregida desde entonces. – mklement0

+1

muy buen punto este tipo 'es necesario en esta línea de comandos, uniq solo elimina las líneas duplicadas que se encuentran inmediatamente después de las otras' que acabo de aprender !! – HattrickNZ

+2

GNU 'sort' presenta una versión' -u' para dar los valores únicos también. – Arthur2e5

9

Tápelos a través de sort y uniq. Esto elimina todos los duplicados.

uniq -d da solo los duplicados, uniq -u da solo los únicos (tiras duplicadas).

+0

tengo que ordenar primero por el aspecto de él – Brabster

+1

Sí, lo hace. O más exactamente, necesita agrupar todas las líneas duplicadas. Sin embargo, la ordenación lo hace por definición;) –

+0

Además, 'uniq -u' NO es el comportamiento predeterminado (ver la edición en mi respuesta para más detalles) –

9

Para los conjuntos de datos más grandes, donde la clasificación puede no ser deseable, también puede utilizar el siguiente script Perl:

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

Esto, básicamente, sólo recuerda cada salida de línea para que no emite de nuevo.

Tiene la ventaja sobre la solución "sort | uniq" en que no se requiere clasificación por adelantado.

+2

Tenga en cuenta que la ordenación de un archivo muy grande no es un problema per se con la ordenación; puede ordenar archivos que son más grandes que el RAM + swap disponible. Perl, OTOH, fallará si solo hay unos pocos duplicados. –

+0

Sí, es una compensación dependiendo de los datos esperados. Perl es mejor para un gran conjunto de datos con muchos duplicados (no se requiere almacenamiento en disco). El enorme conjunto de datos con pocos duplicados debería usar sort (y almacenamiento en disco). Los pequeños conjuntos de datos pueden usar cualquiera. Personalmente, probaría Perl primero, cambiar para ordenar si falla. – paxdiablo

+0

Dado que la ordenación solo le proporciona un beneficio si tiene que intercambiarse al disco. – paxdiablo

9

Con zsh se puede hacer esto:

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 

O puede utilizar AWK:

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

Soluciones inteligentes que no implican ordenar la entrada. Advertencias: La solución 'awk' muy inteligente pero críptica (ver http://stackoverflow.com/a/21200722/45375 para una explicación) funcionará con archivos grandes, siempre que el número de líneas únicas sea pequeño suficiente (ya que las líneas únicas se mantienen en la memoria). La solución 'zsh' primero lee el archivo completo en la memoria, que puede no ser una opción con archivos grandes. Además, tal como está escrito, solo las líneas sin espacios integrados se manejan correctamente; para arreglar esto, use 'IFS = $ '\ n' read -d '' -r -A u mklement0

+0

Correcto. O bien: '(IFS = $ '\ n' u = ($ (

+1

Gracias, eso es más simple (suponiendo que no necesita para establecer las variables necesarias fuera de la subshell). Tengo curiosidad sobre cuándo necesita el sufijo '[@]' para hacer referencia a todos los elementos de una matriz; parece que, al menos a partir de la versión 5, funciona sin ella; o simplemente lo agregaste para mayor claridad? – mklement0

59
./script.sh | sort -u 

Esto es lo mismo que monoxide'sanswer, pero un poco más concisa.

+4

Estás siendo modesto: tu solución también _perform_ better (probablemente solo notable con grandes conjuntos de datos). – mklement0

1

Único, según lo solicitado, (pero no ordenado);
utiliza menos recursos del sistema para menos de ~ 70 elementos (como se prueba con el tiempo);
escrito a tomar la entrada de la entrada estándar,
(o modificar e incluir en otro 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 que puede hacer, creo que es más rápido que el tipo

./yourscript.ksh | awk '!a[$0]++' 
Cuestiones relacionadas