2009-03-06 18 views

Répondre

302

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

 
./yourscript.ksh | sort | uniq 

(Pour votre information, oui, le genre est nécessaire dans cette ligne de commande, uniq les bandes que les lignes en double qui sont immédiatement après l'autre)

EDIT:

Contrairement à ce qui a été posté par Aaron Digulla en fonction des options de ligne de commande de uniq:

Étant donné l'entrée suivante:

 
class 
jar 
jar 
jar 
bin 
bin 
java 

uniq va afficher toutes les lignes exactement une fois:

 
class 
jar 
bin 
java 

uniq -d va afficher toutes les lignes qui apparaissent plus d'une fois, et il les imprimer une fois:

 
jar 
bin 

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

 
class 
java 
+1

Juste un FYI pour les retardataires: @ La réponse d'AaronDigulla a depuis été corrigée. – mklement0

+1

très bon point ce 'tri est nécessaire dans cette ligne de commande, uniq ne bande que des lignes en double qui sont immédiatement après l'autre» que je viens d'apprendre !! – HattrickNZ

+2

GNU 'sort' dispose d'une version' -u' pour donner les valeurs uniques aussi. – Arthur2e5

9

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

uniq -d donne seulement les doublons, uniq -u donne seulement les uniques (bandes dupliquées).

+0

dois trier d'abord par les regards de celui-ci – Brabster

+1

Oui, vous faites. Ou plus exactement, vous devez regrouper toutes les lignes dupliquées. Le tri le fait par définition cependant;) –

+0

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

9

Pour les ensembles de données plus importants 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; }' 

Ce souvient fondamentalement juste chaque sortie de ligne de sorte qu'elle ne sort pas encore.

L'avantage par rapport à la solution "sort | uniq" est qu'il n'y a pas de tri à l'avant.

+2

Notez que le tri d'un très gros fichier n'est pas un problème en soi avec sort; Il peut trier les fichiers plus gros que le RAM + swap disponible. Perl, OTOH, échouera s'il n'y a que peu de doublons. –

+0

Oui, c'est un compromis en fonction des données attendues. Perl est meilleur pour un grand ensemble de données avec beaucoup de doublons (pas de stockage sur disque requis). Un énorme ensemble de données avec peu de doublons devrait utiliser le tri (et le stockage sur disque). Les petits ensembles de données peuvent utiliser l'un ou l'autre. Personnellement, je voudrais d'abord essayer Perl, passer à trier si elle échoue. – paxdiablo

+0

Puisque le tri ne vous procure qu'un avantage si vous devez l'échanger sur disque. – paxdiablo

9

Avec zsh vous pouvez le faire:

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 
+2

Des solutions intelligentes qui n'impliquent pas le tri de l'entrée. Avertissements: La solution 'awk' très astucieuse mais cryptique (voir http://stackoverflow.com/a/21200722/45375 pour une explication) fonctionnera avec des fichiers volumineux tant que le nombre de lignes uniques est petit assez (car les lignes uniques sont gardées en mémoire). La solution 'zsh' lit tout le fichier en mémoire en premier, ce qui peut ne pas être une option avec des fichiers volumineux. En outre, comme écrit, seules les lignes sans espaces incorporés sont traitées correctement; Pour résoudre ce problème, utilisez 'IFS = $ '\ n' lisez -d '' -r -A u mklement0

+0

Correct. Ou: '(IFS = $ '\ n' u = ($ (

+1

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

59
./script.sh | sort -u 

C'est le même que monoxide'sanswer, mais un peu plus concis.

+4

Vous êtes modeste: votre solution sera également plus performante (probablement uniquement visible avec de grands ensembles de données). – mklement0

1

Unique, sur demande, (mais non trié);
utilise moins de ressources système pour moins de ~ 70 éléments (comme testé avec le temps);
écrit à prendre l'entrée 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[@]}" 
2

Avec AWK, vous pouvez le faire, je le trouve plus rapide que sorte

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