J'ai un script ksh qui renvoie une longue liste de valeurs, séparées par une nouvelle ligne, et je souhaite afficher uniquement les valeurs uniques/distinctes. C'est possible de faire ça?
Par exemple, supposons que ma sortie soit un suffixe de fichier dans un répertoire:
tar gz Java gz Java tar class class
Je veux voir une liste comme:
tar gz Java class
Vous voudrez peut-être examiner les applications uniq
et sort
.
./ yourscript.ksh | trier | uniq
(Pour info, oui, le tri est nécessaire dans cette ligne de commande, uniq
ne supprime que les lignes dupliquées qui se suivent immédiatement)
EDIT:
Contrairement à ce qui a été posté par Aaron Digulla par rapport aux options de ligne de commande de uniq
:
Compte tenu de l'entrée suivante:
classe jar jar jar bin bin Java
uniq
affichera toutes les lignes exactement une fois:
classe jar bin Java
uniq -d
affichera toutes les lignes qui apparaissent plusieurs fois et les imprimera une fois:
jar bin
uniq -u
affichera toutes les lignes qui apparaissent exactement une fois et les imprimera une fois:
classe Java
Avec zsh vous pouvez faire ceci:
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
Ou vous pouvez utiliser AWK:
zsh-4.3.9[t]% awk '!_[$0]++' infile
tar
more than one Word
gz
Java
class
Transférez-les dans sort
et uniq
. Cela supprime tous les doublons.
uniq -d
ne donne que les doublons, uniq -u
ne donne que les uniques (les doublons en bandes).
Pour les grands ensembles de données où le tri peut ne pas être souhaitable, vous pouvez également utiliser le script Perl suivant:
./yourscript.ksh | Perl -ne 'if (!defined $x{$_}) { print $_; $x{$_} = 1; }'
En gros, cela ne fait que rappeler chaque sortie de ligne afin qu’elle ne la reproduise plus.
Il présente l’avantage sur la solution "sort | uniq
" en ce qu’aucun tri préalable n’est requis.
Avec AWK, vous pouvez le faire, je le trouve plus rapidement que le tri
./yourscript.ksh | awk '!a[$0]++'
Unique, à la demande (mais non trié);
utilise moins de ressources système pour moins de ~ 70 éléments (testé avec le temps);
écrit pour recevoir les entrées de stdin,
(ou modifier et inclure dans un autre script):
(Frapper)
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[@]}"