Comment obtenir uniquement les résultats uniques sans avoir à trier les données?

40
$ cat data.txt 
aaaaaa
aaaaaa
cccccc
aaaaaa
aaaaaa
bbbbbb
$ cat data.txt | uniq
aaaaaa
cccccc
aaaaaa
bbbbbb
$ cat data.txt | sort | uniq
aaaaaa
bbbbbb
cccccc
$

Le résultat dont j'ai besoin est d' afficher toutes les lignes du fichier d'origine en supprimant tous les doublons (pas uniquement les suivants), tout en maintenant l'ordre d'origine des instructions dans le fichier .

Ici, dans cet exemple, le résultat que je cherchais était

aaaaaa
cccccc
bbbbbb

Comment puis-je effectuer cette uniqopération généralisée en général?

Lazer
la source

Réponses:

54
perl -ne 'print unless $seen{$_}++' data.txt

Ou, si vous devez avoir une utilisation inutile decat :

cat data.txt | perl -ne 'print unless $seen{$_}++'

Voici une awktraduction pour les systèmes dépourvus de Perl:

awk '!seen[$0]++' data.txt
cat data.txt | awk '!seen[$0]++'
cjm
la source
3
Un script awk légèrement plus court est{ if (!seen[$0]++) print }
camh le
1
@fred, à moins que votre fichier ne soit vraiment énorme, l'une ou l'autre version prend plus de temps à saisir qu'à exécuter.
cjm
8
La version awk peut être encore plus court en laissant les if, print, les parenthèses et les accolades:awk '!seen[$0]++'
Gordon Davisson
2
@Legate, c'est le nom d' un tableau dans lequel nous enregistrons chaque ligne que nous avons vue. Vous pouvez le changer '!LarryWall[$0]++'pour tous les soucis, mais "vu" aide les gens à mieux comprendre le programme.
cjm
1
@Sadi, cela aurait vraiment dû être posé comme une question, pas comme un commentaire. Mais certaines lignes de ce fichier se terminent par un espace, d'autres non. Ces commandes considèrent la ligne entière comme significative, y compris les espaces à la fin.
cjm
13

John a un outil appelé unique:

usr@srv % cat data.txt | unique out
usr@srv % cat out
aaaaaa
cccccc
bbbbbb

Obtenir la même chose sans outils supplémentaires dans une seule ligne de commande est un peu plus complexe:

usr@srv % cat data.txt | nl | sort -k 2 | uniq -f 1 | sort -n | sed 's/\s*[0-9]\+\s\+//'
aaaaaa
cccccc
bbbbbb

nlimprime les numéros de ligne devant les lignes, donc si nous sort/ uniqderrière elles, nous pouvons restaurer l’ordre initial des lignes. sedsupprime simplement les numéros de ligne par la suite;)

binfale
la source
Existe-t-il une combinaison de commandes linux communes pouvant faire la même chose?
Lazer
7
Qu'est-ce qui vous a manqué "sans avoir à trier les données"?
Totor
@Totor - voir la réponse de menkus à un commentaire similaire. @binfalse - votre deuxième solution ne fonctionne pas (peut-être que cela fonctionne avec cet exemple trivial mais cela ne fonctionne pas avec une entrée réelle). Veuillez corriger cela, par exemple, cela devrait toujours fonctionner:nl -ba -nrz data.txt | sort -k2 -u | sort | cut -f2
don_crissti
6

Je préfère utiliser ceci:

cat -n data.txt | sort --key=2.1 -b -u | sort -n | cut -c8-

cat -n ajoute des numéros de ligne,

sort --key=2.1 -b -u trie sur le deuxième champ (après les numéros de ligne ajoutés), en ignorant les espaces en début de ligne, en conservant des lignes uniques

sort -n trie dans un ordre numérique strict

cut -c8- conservez tous les caractères de la colonne 8 dans EOL (c.-à-d., omettez les numéros de ligne que nous avons inclus)

menkus
la source
5
> Comment obtenir uniquement les résultats uniques sans avoir à trier les données? > sans avoir à trier les données
Jan Wikholm
7
'sans avoir à trier les données' apparaît uniquement dans le titre. Le besoin réel est de: "afficher toutes les lignes du fichier d'origine en supprimant tous les doublons (pas seulement les consécutifs), tout en maintenant l'ordre d'origine des instructions dans le fichier".
menkus
1
@menkus la clé est "tout en maintenant l'ordre d'origine des instructions dans le fichier". Cette réponse ne permet pas cela.
Andrew Ferrier
2

Perl a un module que vous pouvez utiliser qui inclut une fonction appelée uniq. Donc, si vous avez chargé vos données dans un tableau en Perl, vous appelez simplement la fonction comme ceci pour la rendre unique, tout en maintenant la commande d'origine.

use List::MoreUtils qw(uniq)    
@output = uniq(@output);

Vous pouvez en savoir plus sur ce module ici: Liste :: MoreUtils

slm
la source
Peut-il gérer d’énormes fichiers, par exemple 500 Go?
Garçon