web-dev-qa-db-fra.com

Sélectionnez des valeurs uniques ou distinctes dans une liste du script UNIX Shell

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
212
brabster

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 
386
Matthew Scharley
./script.sh | sort -u

C'est la même chose que monoxyderéponse , mais un peu plus concis.

80
gpojd

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
9
Dimitre Radoulov

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).

9
Aaron Digulla

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.

9
paxdiablo

Avec AWK, vous pouvez le faire, je le trouve plus rapidement que le tri

 ./yourscript.ksh | awk '!a[$0]++'
6
Ajak6

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[@]}"
1
FGrose