У меня есть ссылки в виде текстового файла с длинным списком записей, и у каждого есть два (или более) поля.
Первый столбец - это URL ссылки; второй столбец - это заголовок, который может немного отличаться в зависимости от того, как была сделана запись. То же самое для третьего поля, которое может присутствовать или не присутствовать.
Я хочу идентифицировать, но не удалять записи, в которых первое поле (ссылочный URL) идентично. Я знаю о sort -k1,1 -u
, но это автоматически (не в интерактивном режиме) удалит все, кроме первого попадания. Есть ли способ просто дать мне знать, чтобы я мог выбрать, какой из них сохранить?
В приведенном ниже фрагменте трех строк, имеющих одно и то же первое поле (http://unix.stackexchange.com/questions/49569/
), я хотел бы оставить строку 2, потому что у него есть дополнительные теги (sort, CLI) и удаляются строки № 1 и № 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
Существует ли программа, помогающая идентифицировать такие «дубликаты»? Затем я могу вручную очистить, удалив лично строки 1 и 3?
Если я понимаю Ваш вопрос, я думаю, что Вам нужно что-то как:
for dup in $(sort -k1,1 -u file.txt | cut -d' ' -f1); do grep -n -- "$dup" file.txt; done
или:
for dup in $(cut -d " " -f1 file.txt | uniq -d); do grep -n -- "$dup" file.txt; done
, где file.txt
Ваш файл, содержащий данные о Вас, интересно.
В выводе Вы будете видеть количество строк и строк, где первое поле найдено два или больше раза.
Это - классическая проблема, которая может быть решена с uniq
команда. uniq
может обнаружить дублирующиеся последовательные строки и удалить дубликаты (-u
, --unique
) или сохраните дубликаты только (-d
, --repeated
).
Начиная с упорядочивания дублирующихся строк не важно для Вас, необходимо отсортировать его сначала. Затем используйте uniq
распечатать уникальные строки только:
sort yourfile.txt | uniq -u
Существует также a -c
(--count
) опция, которая печатает количество дубликатов для -d
опция. См. страницу руководства uniq
для деталей.
Если Вы действительно не заботитесь о частях после первого поля, можно использовать следующую команду для нахождения, делают дубликаты ключа и печатают каждый номер строки для него (добавьте другого | sort -n
отсортировать вывод с методической точностью):
cut -d ' ' -f1 .bash_history | nl | sort -k2 | uniq -s8 -D
Так как Вы хотите видеть дублирующиеся строки (использующий первое поле в качестве ключа), Вы не можете непосредственно использовать uniq
. Проблема, которые делают автоматизацию трудной, - то, что части заголовка варьируются, но программа не может автоматически определить, какой заголовок нужно считать заключительным.
Вот сценарий AWK (сохраните его к script.awk
) это берет Ваш текстовый файл в качестве входа и печатает все дублирующиеся строки, таким образом, можно решить, чтобы удалить. (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];
}
}
}
}
Если я считал это правильно, все, в чем Вы нуждаетесь, что-то как
awk '{print $1}' file | sort | uniq -c |
while read num dupe; do [[ $num > 1 ]] && grep -n -- "$dupe" file; done
Это распечатает количество строки, которая содержит простофилю и саму строку. Например, использование этого файла:
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
Это произведет этот вывод:
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
Для печати только количества строки Вы могли сделать
awk '{print $1}' file | sort | uniq -c |
while read num dupe; do [[ $num > 1 ]] && grep -n -- "$dupe" file; done | cut -d: -f 1
И распечатать только строку:
awk '{print $1}' file | sort | uniq -c |
while read num dupe; do [[ $num > 1 ]] && grep -n -- "$dupe" file; done | cut -d: -f 2-
Объяснение:
awk
сценарий просто печатает разделенное поле 1-го пространства файла. Использовать $N
распечатать поле Nth. sort
сортирует его и uniq -c
считает случаи каждой строки.
Это затем передается while
цикл, который сохраняет количество случаев как $num
и строка как $dupe
и если $num
больше, чем один (таким образом, это дублировано, по крайней мере, однажды), это будет искать файл ту строку, с помощью -n
распечатать номер строки. --
говорит grep
это, что следует, не является параметром командной строки, полезным для когда $dupe
может запуститься с -
.
Несомненно самый подробный в списке, могло, вероятно, быть короче:
#!/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)
дает на текстовом файле как:
monkey banana
dog bone
monkey banana peanut
cat mice
dog cowmeat
вывод как:
found duplicates:
-----------------
dog [1, 4]
[1] dog bone
[4] dog cowmeat
monkey [0, 2]
[0] monkey banana
[2] monkey banana peanut
После того как Вы выбрали строки для удаления:
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)
Посмотрите следующий отсортированный file.txt
:
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
, поскольку список короток, я вижу (после сортировки), что существует три набора дубликатов.
Затем например, я могу принять решение сохранить:
askubuntu.com/q/53762 ::: How to use lm-sensors?
, а не
askubuntu.com/q/53762 ::: how-to-use-to-use-lm-sensors
, Но для более длинного списка это будет трудно. На основе двух ответов одно предложение uniq
и другое предложение cut
, я нахожу, что эта команда дает мне вывод, который я хотел бы:
$ cut -d " " -f1 file.txt | uniq -d
askubuntu.com/q/53762
stackoverflow.com/q/4594319
wiki.ubuntu.com/ClipboardPersistence
$
Ее то, как я решил его:
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
Файл, отсортированный и дедуплицированный столбцами 1 и 2:
sort -t',' -k1,1 -k2,2 -u file_with_duplicates
Файл, отсортированный только по столбцам 1 и 2:
sort -t',' -k1,1 -k2,2 file_with_duplicates
Шоу различие только:
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