Comment conserver le format d'un fichier si vous utilisez la commande uniq (en shell)?
-
22-07-2019 - |
Question
Pour utiliser la commande uniq, vous devez d'abord trier votre fichier.
Mais dans le fichier que j'ai, l'ordre des informations est important. Comment puis-je conserver le format d'origine du fichier tout en supprimant le contenu dupliqué?
La solution
Une autre version d'awk:
awk '!_[<*>]++' infile
Autres conseils
Ce awk
conserve la première occurrence. Même algorithme que les autres réponses utilisent:
awk '!(sort file | uniq -d | awk '
FNR == NR { dups[<*>] }
FNR != NR && (!(<*> in dups) || !lines[<*>]++)
' - file
in lines) { print <*>; lines[<*>]; }'
En voici un qui n'a besoin que de stocker les lignes dupliquées (par opposition à toutes les lignes) en utilisant awk
:
Il existe également le "numéro de ligne, tri double". méthode.
nl -n ln | sort -u -k 2| sort -k 1n | cut -f 2-
Vous pouvez exécuter uniq -d sur la version triée du fichier pour rechercher les lignes en double, puis exécuter un script indiquant:
if this_line is in duplicate_lines {
if not i_have_seen[this_line] {
output this_line
i_have_seen[this_line] = true
}
} else {
output this_line
}
Utiliser uniquement uniq et grep:
Créer un fichier dsh:
#!/bin/sh
sort $1 | uniq > $1_uniq
for line in $(cat $1); do
cat $1_uniq | grep -m1 $line >> $1_out
cat $1_uniq | grep -v $line > $1_uniq2
mv $1_uniq2 $1_uniq
done;
rm $1_uniq
Exemple:
./d.sh infile
Vous pouvez utiliser une horrible chose O (n ^ 2), comme ceci (pseudo-code):
file2 = EMPTY_FILE
for each line in file1:
if not line in file2:
file2.append(line)
Ceci est potentiellement assez lent, surtout s’il est implémenté au niveau Bash. Mais si vos fichiers sont raisonnablement courts, cela fonctionnera probablement très bien et sera rapide à mettre en œuvre ( pas la ligne dans le fichier 2
est alors juste grep -v
, etc.). ).
Sinon, vous pourriez bien sûr coder un programme dédié en utilisant une structure de données plus avancée en mémoire pour l'accélérer.
for line in $(sort file1 | uniq ); do
grep -n -m1 line file >>out
done;
sort -n out
d'abord faire le tri,
pour chaque valeur unitaire grep pour la première correspondance (-m1)
et conservez les numéros de ligne
trie la sortie numériquement (-n) par numéro de ligne.
vous pouvez ensuite supprimer la ligne # avec Sed ou awk