Sélectionnez des valeurs uniques ou distinctes dans une liste dans un script shell UNIX

StackOverflow https://stackoverflow.com/questions/618378

Question

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 souhaite voir une liste comme celle-ci:

tar
gz
java
class
Était-ce utile?

La solution

Vous voudrez peut-être examiner les applications uniq et sort .

./yourscript.ksh | sort | 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 en relation avec les options de ligne de commande de uniq :

Étant donné l'entrée suivante:

class
jar
jar
jar
bin
bin
java

uniq affichera toutes les lignes exactement une fois:

class
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:

class
java

Autres conseils

./script.sh | sort -u

Identique à monoxide's répondre , mais un peu plus concis.

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{

Pour les grands ensembles de données où le tri peut ne pas être souhaitable, vous pouvez également utiliser le script Perl suivant:

<*>

En gros, cela ne fait que rappeler chaque sortie de ligne afin qu'elle ne la reproduise plus.

Il présente l'avantage par rapport au tri & < | uniq " solution en ce qu'il n'y a aucun tri requis à l'avant.

}) { print

Pour les grands ensembles de données où le tri peut ne pas être souhaitable, vous pouvez également utiliser le script Perl suivant:

<*>

En gros, cela ne fait que rappeler chaque sortie de ligne afin qu'elle ne la reproduise plus.

Il présente l'avantage par rapport au tri & < | uniq " solution en ce qu'il n'y a aucun tri requis à l'avant.

; $x{

Pour les grands ensembles de données où le tri peut ne pas être souhaitable, vous pouvez également utiliser le script Perl suivant:

<*>

En gros, cela ne fait que rappeler chaque sortie de ligne afin qu'elle ne la reproduise plus.

Il présente l'avantage par rapport au tri & < | uniq " solution en ce qu'il n'y a aucun tri requis à l'avant.

} = 1; }'

En gros, cela ne fait que rappeler chaque sortie de ligne afin qu'elle ne la reproduise plus.

Il présente l'avantage par rapport au tri & < | uniq " solution en ce qu'il n'y a aucun tri requis à l'avant.

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 '!_[<*>]++' 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 n'en donne que les uniques (bandes en double).

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

 ./yourscript.ksh | awk '!a[<*>]++'

Unique, comme demandé, (mais non trié);
utilise moins de ressources système pour moins de ~ 70 éléments (comme testé avec le temps);
écrit pour recevoir les commentaires de stdin,
(ou modifier et inclure dans un autre 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[@]}"
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top