298 votes

Sélectionner des valeurs uniques ou distinctes dans une liste dans le shell UNIX script.

J'ai un script ksh qui retourne une longue liste de valeurs, séparées par des nouvelles lignes, et je veux voir uniquement les valeurs uniques/distinctes. Est-il possible de faire cela ?

Par exemple, disons que mon résultat est constitué de suffixes de fichiers dans un répertoire :

tar
gz
java
gz
java
tar
class
class

Je veux voir une liste comme :

tar
gz
java
class

527voto

Matthew Scharley Points 43262

Vous pouvez consulter le uniq y sort applications.

./yourscript.ksh | sort | uniq

(Pour info, oui, le tri est nécessaire dans cette ligne de commande, uniq ne dépouille que les lignes dupliquées qui se suivent immédiatement)

EDITAR:

Contrairement à ce qui a été posté par Aaron Digulla en ce qui concerne uniq Les options de la ligne de commande de l'utilisateur :

É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 sortira toutes les lignes qui apparaissent plus d'une fois, et il les imprimera une fois :

jar
bin

uniq -u sortira toutes les lignes qui apparaissent exactement une fois, et il les imprimera une fois :

class
java

2 votes

Juste un FYI pour les retardataires : La réponse de @AaronDigulla a depuis été corrigée.

3 votes

Très bon point ce `tri est nécessaire dans cette ligne de commande, uniq ne supprime que les lignes dupliquées qui sont immédiatement après l'autre` ce que je viens d'apprendre ! !!

4 votes

GNU sort comporte un -u pour donner les valeurs uniques également.

104voto

gpojd Points 12043
./script.sh | sort -u

C'est la même chose que du monoxyde de carbone réponse mais un peu plus concis.

10 votes

Vous êtes modeste : votre solution va également effectuer meilleure (probablement seulement perceptible avec de grands ensembles de données).

0 votes

Je pense que cela devrait être plus efficace que ... | sort | uniq parce qu'elle est exécutée en une seule fois

2 votes

@AdrianAntunez peut-être que c'est aussi parce que la sort -u n'a pas besoin de mettre à jour la liste triée à chaque fois qu'il trouve une valeur antérieure déjà rencontrée. alors que la fonction sort | doit trier tous avant de le transmettre à uniq

15voto

Dimitre Radoulov Points 9185

Avec zsh vous pouvez le faire :

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

% awk '!_[$0]++' infile    
tar
more than one word
gz
java
class

2 votes

Des solutions astucieuses qui n'impliquent pas de trier les entrées. Avertissements : Le très astucieux mais cryptique awk (voir stackoverflow.com/a/21200722/45375 pour une explication) fonctionnera avec des fichiers volumineux tant que le nombre de lignes uniques est suffisamment petit (car les lignes uniques sont conservées en mémoire). Le site zsh lit d'abord l'intégralité du fichier en mémoire, ce qui peut ne pas être une option pour les fichiers volumineux. De plus, tel qu'il est écrit, seules les lignes sans espace incorporé sont traitées correctement ; pour corriger cela, utilisez IFS=$'\n' read -d '' -r -A u <file; print -l ${(u)u} à la place.

0 votes

Correct. Ou : (IFS=$'\n' u=($(<infile)); print -l "${(u)u[@]}")

1 votes

Merci, c'est plus simple (en supposant que vous n'avez pas besoin de définir des variables nécessaires en dehors du sous-shell). Je suis curieux de savoir quand vous avez besoin de l'option [@] pour référencer tous les éléments d'un tableau - il semble que - au moins à partir de la version 5 - il fonctionne sans ce suffixe ; ou l'avez-vous simplement ajouté pour plus de clarté ?

11voto

paxdiablo Points 341644

Pour les ensembles de données plus importants où le tri n'est pas forcément souhaitable, vous pouvez également utiliser le script perl suivant :

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

Cela permet de mémoriser chaque ligne sortie afin de ne pas la sortir à nouveau.

Il a l'avantage sur le " sort | uniq Il s'agit d'une solution " à la carte " dans la mesure où aucun tri n'est nécessaire au départ.

2 votes

Notez que le tri d'un très gros fichier n'est pas un problème en soi avec sort ; il peut trier des fichiers qui sont plus gros que la RAM+swap disponible. Perl, par contre, échouera s'il n'y a que quelques doublons.

1 votes

Oui, c'est un compromis qui dépend des données attendues. Perl est meilleur pour les grands ensembles de données avec beaucoup de doublons (pas de stockage sur disque nécessaire). Les grands ensembles de données avec peu de doublons devraient utiliser le tri (et le stockage sur disque). Les petits ensembles de données peuvent utiliser l'un ou l'autre. Personnellement, j'essaierais d'abord Perl, puis je passerais à sort si cela échoue.

0 votes

Puisque le tri ne vous donne un avantage que s'il doit être échangé sur le disque.

11voto

Aaron Digulla Points 143830

Passez-les à travers sort y uniq . Cela supprime tous les doublons.

uniq -d ne donne que les doublons, uniq -u ne donne que les uniques (élimine les doublons).

0 votes

Il faut d'abord trier, à ce qu'il semble.

1 votes

Si, vous le savez. Ou plus exactement, vous devez regrouper toutes les lignes en double. Le tri le fait par définition ;)

0 votes

Aussi, uniq -u n'est PAS le comportement par défaut (voir la modification de ma réponse pour plus de détails).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X