Seleccione valores únicos o distintos de una lista en el script de shell de UNIX
Pregunta
Tengo un script ksh que devuelve una larga lista de valores, separados por una nueva línea, y quiero ver solo los valores únicos / distintos. ¿Es posible hacer esto?
Por ejemplo, diga que mi salida es sufijos de archivos en un directorio:
tar gz java gz java tar class class
Quiero ver una lista como:
tar gz java class
Solución
Es posible que desee ver las aplicaciones uniq
y sort
.
./yourscript.ksh | sort | uniq
(Para su información, sí, la clasificación es necesaria en esta línea de comandos, uniq
solo elimina las líneas duplicadas que están inmediatamente una detrás de la otra)
EDIT:
Al contrario de lo que se ha publicado por Aaron Digulla en relación con las opciones de línea de comandos de uniq
:
Dada la siguiente entrada:
class jar jar jar bin bin java
uniq
emitirá todas las líneas exactamente una vez:
class jar bin java
uniq -d
mostrará todas las líneas que aparecen más de una vez, y las imprimirá una vez:
jar bin
uniq -u
mostrará todas las líneas que aparecen exactamente una vez, y las imprimirá una vez:
class java
Otros consejos
./script.sh | sort -u
Esto es lo mismo que monoxide's respuesta , pero un poco más conciso.
Para conjuntos de datos más grandes donde la clasificación puede no ser conveniente, también puede usar el siguiente script de Perl:
./yourscript.ksh | perl -ne 'if (!defined $x{ Para conjuntos de datos más grandes donde la clasificación puede no ser conveniente, también puede usar el siguiente script de Perl:
<*>
Básicamente, esto solo recuerda cada salida de línea para que no vuelva a emitirla.
Tiene la ventaja sobre el " sort | uniq
" La solución es que no se requiere clasificación por adelantado.
}) { print Para conjuntos de datos más grandes donde la clasificación puede no ser conveniente, también puede usar el siguiente script de Perl:
<*>
Básicamente, esto solo recuerda cada salida de línea para que no vuelva a emitirla.
Tiene la ventaja sobre el " sort | uniq
" La solución es que no se requiere clasificación por adelantado.
; $x{ Para conjuntos de datos más grandes donde la clasificación puede no ser conveniente, también puede usar el siguiente script de Perl:
<*>
Básicamente, esto solo recuerda cada salida de línea para que no vuelva a emitirla.
Tiene la ventaja sobre el " sort | uniq
" La solución es que no se requiere clasificación por adelantado.
} = 1; }'
Básicamente, esto solo recuerda cada salida de línea para que no vuelva a emitirla.
Tiene la ventaja sobre el " sort | uniq
" La solución es que no se requiere clasificación por adelantado.
Con zsh puedes 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 puedes usar AWK:
zsh-4.3.9[t]% awk '!_[<*>]++' infile
tar
more than one word
gz
java
class
Colóquelos en sort
y uniq
. Esto elimina todos los duplicados.
uniq -d
proporciona solo los duplicados, uniq -u
proporciona solo los únicos (tiras de duplicados).
Con AWK puedes hacerlo, lo encuentro más rápido que ordenar
./yourscript.ksh | awk '!a[<*>]++'
Único, según lo solicitado, (pero no clasificado);
utiliza menos recursos del sistema para menos de ~ 70 elementos (según lo probado con el tiempo);
escrito para tomar entrada de stdin,
(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[@]}"