J'ai mes références sous forme de fichier texte avec une longue liste d'entrées et chacune a deux champs (ou plus).
La première colonne est l'URL de la référence; la deuxième colonne est le titre qui peut varier un peu en fonction de la manière dont l'entrée a été effectuée. Idem pour le troisième champ qui peut être ou ne pas être présent.
Je souhaite identifier mais pas supprimer les entrées dont le premier champ (URL de référence) est identique. Je sais à propos de sort -k1,1 -u
mais cela supprimera automatiquement (de manière non interactive) tout sauf le premier hit. Y a-t-il un moyen de me le faire savoir afin que je puisse choisir lequel retenir?
Dans l'extrait ci-dessous de trois lignes qui ont le même premier champ (http://unix.stackexchange.com/questions/49569/
), j'aimerais conserver la ligne 2 car elle comporte des balises supplémentaires (sort, CLI) et supprimer les lignes n ° 1 et n ° 3:
http://unix.stackexchange.com/questions/49569/ unique-lines-based-on-the-first-field
http://unix.stackexchange.com/questions/49569/ Unique lines based on the first field sort, CLI
http://unix.stackexchange.com/questions/49569/ Unique lines based on the first field
Existe-t-il un programme pour aider à identifier de tels "doublons"? Ensuite, je peux nettoyer manuellement en supprimant personnellement les lignes 1 et 3?
Si je comprends votre question, je pense que vous avez besoin de quelque chose comme:
for dup in $(sort -k1,1 -u file.txt | cut -d' ' -f1); do grep -n -- "$dup" file.txt; done
ou:
for dup in $(cut -d " " -f1 file.txt | uniq -d); do grep -n -- "$dup" file.txt; done
où file.txt
est votre fichier contenant des données vous concernant.
Dans la sortie, vous verrez le nombre de lignes et de lignes où le premier champ est trouvé deux fois ou plus.
Il s'agit d'un problème classique qui peut être résolu avec la commande uniq
name__. uniq
peut détecter les doublons consécutifs lignes et supprimer les doublons (-u
, --unique
) ou ne conserver que les doublons (-d
, --repeated
).
Comme la commande de doublons de lignes n’est pas importante pour vous, vous devez d’abord la trier. Utilisez ensuite uniq
pour n’imprimer que des lignes uniques:
sort yourfile.txt | uniq -u
Il existe également une option -c
(--count
) qui affiche le nombre de doublons pour l'option -d
. Consultez la page de manuel de uniq
pour plus de détails.
Si vous ne vous souciez vraiment pas des parties après le premier champ, vous pouvez utiliser la commande suivante pour rechercher les clés en double et imprimer chaque numéro de ligne correspondant (ajoutez un autre | sort -n
pour que le résultat soit trié par ligne):
cut -d ' ' -f1 .bash_history | nl | sort -k2 | uniq -s8 -D
Puisque vous voulez voir les lignes en double (en utilisant le premier champ comme clé), vous ne pouvez pas utiliser directement uniq
name__. Le problème qui rend l'automatisation difficile est que les parties du titre varient, mais un programme ne peut pas déterminer automatiquement quel titre doit être considéré comme le titre final.
Voici un script AWK (enregistrez-le dans script.awk
) qui prend votre fichier texte en entrée et imprime toutes les lignes en double afin que vous puissiez choisir les fichiers à supprimer. (awk -f script.awk yourfile.txt
)
#!/usr/bin/awk -f
{
# Store the line ($0) grouped per URL ($1) with line number (NR) as key
lines[$1][NR] = $0;
}
END {
for (url in lines) {
# find lines that have the URL occur multiple times
if (length(lines[url]) > 1) {
for (lineno in lines[url]) {
# Print duplicate line for decision purposes
print lines[url][lineno];
# Alternative: print line number and line
#print lineno, lines[url][lineno];
}
}
}
}
Si je lis ceci correctement, tout ce dont vous avez besoin est quelque chose comme
awk '{print $1}' file | sort | uniq -c |
while read num dupe; do [[ $num > 1 ]] && grep -n -- "$dupe" file; done
Cela affichera le numéro de la ligne contenant la dupe et la ligne elle-même. Par exemple, en utilisant ce fichier:
foo bar baz
http://unix.stackexchange.com/questions/49569/ unique-lines-based-on-the-first-field
bar foo baz
http://unix.stackexchange.com/questions/49569/ Unique lines based on the first field sort, CLI
baz foo bar
http://unix.stackexchange.com/questions/49569/ Unique lines based on the first field
Il produira cette sortie:
2:http://unix.stackexchange.com/questions/49569/ unique-lines-based-on-the-first-field
4:http://unix.stackexchange.com/questions/49569/ Unique lines based on the first field sort, CLI
6:http://unix.stackexchange.com/questions/49569/ Unique lines based on the first field
Pour imprimer uniquement le numéro de la ligne, vous pouvez faire
awk '{print $1}' file | sort | uniq -c |
while read num dupe; do [[ $num > 1 ]] && grep -n -- "$dupe" file; done | cut -d: -f 1
Et pour n'imprimer que la ligne:
awk '{print $1}' file | sort | uniq -c |
while read num dupe; do [[ $num > 1 ]] && grep -n -- "$dupe" file; done | cut -d: -f 2-
Explication:
Le script awk
imprime simplement le premier champ du fichier séparé par des espaces. Utilisez $N
pour imprimer le Nième champ. sort
le trie et uniq -c
compte les occurrences de chaque ligne.
Ceci est ensuite passé à la boucle while
qui enregistre le nombre d’occurrences sous le nom $num
et la ligne sous le nom $dupe
. Si $num
est supérieur à un (il est donc dupliqué au moins une fois), il recherchera cette ligne dans le fichier, en utilisant -n
pour l’afficher. numéro de ligne. --
indique à grep
que ce qui suit n'est pas une option de ligne de commande, utile lorsque $dupe
peut commencer par -
.
Nul doute que le plus verbeux de la liste pourrait probablement être plus court:
#!/usr/bin/python3
import collections
file = "file.txt"
def find_duplicates(file):
with open(file, "r") as sourcefile:
data = sourcefile.readlines()
splitlines = [
(index, data[index].split(" ")) for index in range(0, len(data))
]
lineheaders = [item[1][0] for item in splitlines]
dups = [x for x, y in collections.Counter(lineheaders).items() if y > 1]
dupsdata = []
for item in dups:
occurrences = [
splitlines_item[0] for splitlines_item in splitlines\
if splitlines_item[1][0] == item
]
corresponding_lines = [
"["+str(index)+"] "+data[index] for index in occurrences
]
dupsdata.append((occurrences, corresponding_lines))
# printing output
print("found duplicates:\n"+"-"*17)
for index in range(0, len(dups)):
print(dups[index], dupsdata[index][0])
lines = [item for item in dupsdata[index][1]]
for line in lines:
print(line, end = "")
find_duplicates(file)
donne sur un fichier texte comme:
monkey banana
dog bone
monkey banana peanut
cat mice
dog cowmeat
une sortie comme:
found duplicates:
-----------------
dog [1, 4]
[1] dog bone
[4] dog cowmeat
monkey [0, 2]
[0] monkey banana
[2] monkey banana peanut
Une fois que vous avez choisi les lignes à supprimer:
removelist = [2,1]
def remove_duplicates(file, removelist):
removelist = sorted(removelist, reverse=True)
with open(file, "r") as sourcefile:
data = sourcefile.readlines()
for index in removelist:
data.pop(index)
with open(file, "wt") as sourcefile:
for line in data:
sourcefile.write(line)
remove_duplicates(file, removelist)
Voici comment je l'ai résolu:
file_with_duplicates:
1,a,c
2,a,d
3,a,e <--duplicate
4,a,t
5,b,k <--duplicate
6,b,l
7,b,s
8,b,j
1,b,l
3,a,d <--duplicate
5,b,l <--duplicate
Fichier trié et déduit par les colonnes 1 et 2:
sort -t',' -k1,1 -k2,2 -u file_with_duplicates
Fichier trié uniquement par colonnes 1 et 2:
sort -t',' -k1,1 -k2,2 file_with_duplicates
Montrer seulement la différence:
diff <(sort -t',' -k1,1 -k2,2 -u file_with_duplicates) <(sort -t',' -k1,1 -k2,2 file_with_duplicates)
3a4
3,a,d
6a8
5,b,l
Voir le file.txt
trié suivant:
addons.mozilla.org/en-US/firefox/addon/click-to-play-per-element/ ::: C2P per-element
addons.mozilla.org/en-us/firefox/addon/prospector-oneLiner/ ::: OneLiner
askubuntu.com/q/21033 ::: What is the difference between gksudo and gksu?
askubuntu.com/q/21148 ::: openoffice calc sheet tabs (also askubuntu.com/q/138623)
askubuntu.com/q/50540 ::: What is Ubuntu's Definition of a "Registered Application"?
askubuntu.com/q/53762 ::: How to use lm-sensors?
askubuntu.com/q/53762 ::: how-to-use-to-use-lm-sensors
stackoverflow.com/q/4594319 ::: bash - Shell replace cr\lf by comma
stackoverflow.com/q/4594319 ::: Shell replace cr\lf by comma
wiki.ubuntu.com/ClipboardPersistence ::: ClipboardPersistence
wiki.ubuntu.com/ClipboardPersistence ::: ClipboardPersistence - Ubuntu Wiki
www.youtube.com/watch?v=1olY5Qzmbk8 ::: Create new mime types in Ubuntu
www.youtube.com/watch?v=2hu9JrdSXB8 ::: Change mouse cursor
www.youtube.com/watch?v=Yxfa2fXJ1Wc ::: Mouse cursor size
Comme la liste est courte, je peux voir (après le tri) qu'il existe trois jeux de doublons.
Ensuite, par exemple, je peux choisir de conserver:
askubuntu.com/q/53762 ::: How to use lm-sensors?
plutôt que
askubuntu.com/q/53762 ::: how-to-use-to-use-lm-sensors
Mais pour une liste plus longue, ce sera difficile. Sur la base des deux réponses, l’une suggérant uniq
et l’autre suggérant cut
, je constate que cette commande me donne le résultat souhaité:
$ cut -d " " -f1 file.txt | uniq -d
askubuntu.com/q/53762
stackoverflow.com/q/4594319
wiki.ubuntu.com/ClipboardPersistence
$