У меня есть мои ссылки как текстовый файл с длинным списком записей, и у каждого из них два (или более) поля.
Первый столбец - это URL ссылки; второй столбец - это название, которое может немного отличаться в зависимости от того, как была сделана запись. То же самое для третьего поля, которое может быть или не быть.
Я хочу идентифицировать, но не удалять записи, у которых первое поле (ссылочный URL) идентично. Я знаю о sort -k1,1 -u, но это автоматически (не интерактивно) удаляет все, кроме первого удара. Есть ли способ просто сообщить мне, чтобы я мог выбрать, что сохранить?
В выдержке ниже трех строк, которые имеют одно и то же первое поле (http://unix.stackexchange.com/questions/49569/), я хотел бы оставить строку 2 потому что у него есть дополнительные теги (сортировка, 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?
Это классическая проблема, которая может быть решена с помощью команды uniq. uniq может обнаруживать повторяющиеся последовательные строки и удалять дубликаты (-u, --unique) или сохранять только дубликаты (-d, --repeated).
Поскольку порядок дублирования строк не важен для вы, вы должны отсортировать его в первую очередь. Затем используйте uniq для печати только уникальных строк:
sort yourfile.txt | uniq -u
Также имеется опция -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
Чтобы напечатать только номер строки, вы можете сделать
[ f4]И напечатать только строку:
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 для печати N-го поля. sort сортирует его, а uniq -c подсчитывает вхождения каждой строки.
Затем он передается в цикл while, который сохраняет число вхождений как $num, а строка - как $dupe, а если $num больше единицы (поэтому она дублируется по крайней мере один раз ), он будет искать файл для этой строки, используя -n для печати номера строки. [F15] сообщает 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
, выход: 2]
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