unique - фильтрация дубликатов силами легендарного взломщика


bliznezz аватар

bliznezz - Posted on 15 Апрель 2009

искал способ убирать дубликаты строчек из файла.
привычный спобос

cat file_with_dupe | sort | uniq > distinct

не подходит, т.к. сбивает оригинальную сортировку.
помощь получил, с неожиданной стороны: легендарый взломщик паролей John The Ripper имеет в себе нужный мне функционал.
содержит утилитку unique, которая хоть и является симлинком на john, но вызывая её - получаю именно тот сортировщик:

cat file_with_dupe | ./unique distinct

к сожалению работает только в таком синтаксисе единственный параметр OUTPUT_FILE : принимает поток с stdin и отдает фильтрованный результат в файл OUTPUT_FILE

5
Ваша оценка: Ничего Рейтинг: 5 (1 vote)

если подфиксить в исходниках john the ripper
в файле unique.c, в функции static void unique_init(char *name)
изменить проверку

       if ((fd = open(name, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0)

на

       if ((fd = open(name, O_RDWR |  O_EXCL, 0600)) < 0)

тогда собрав john, можно в качесве параметра давать существующие файлы, пайпы, девайс /dev/stdout например.

однако потестив:

time perl -lne'$x{$_}++||print' < example.txt 1>&- 
real    0m33.592s
user    0m32.768s
sys     0m0.465s
 
time awk '{ if (!x[$0]) { print $0; x[$0]=1 } }' < example.txt 1>&- 
real    0m18.620s
user    0m17.805s
sys     0m0.367s
 
time unique /dev/stdout < example.txt 1>&- 
real    0m33.331s
user    0m30.506s
sys     0m0.732s

мне стало обидно за Кернигана и Риччи.

Спасибо, а то я вечно изобретал что-то вроде cat -n | sort -u -k2 | sort -n
и ломал голову, как покрасивее отрезать потом номера.

Интересно, насколько надёжны оба способа -- с awk и unique?

>искал способ убирать дубликаты строчек из файла.
>привычный спобос
>cat file_with_dupe | sort | uniq > distinct

а почему просто не
at file_with_dupe | sort -u > distinct

?

ты бы попробовал? Ж:-)
sort делает "уникальными" только строки идущие рядом. тоесть надо сначала перед sort -u отсортировать эти строки

cat file_with_dupe |awk '!t[$0] { t[$0]=1; print }'

помоему не хорошо призывая учить awk давать код, которым только что новичков и отпугивать. ведь можно было бы и по понятному типа:

# используем "массивы" awk, аналог хешей в perl.
# t это массив в котором как индекс используется текущая строка,
# если в элементе этого массива что то есть, то эта строка уже была
$ printf "1\n2\n1\n" |awk '{ if (!t[$0]) { t[$0]=1; print }}'

PS
если говорить не о новичках, то так короче Ж:-)

$ printf "1\n2\n1\n" |awk '!t[$0]++{print}'

Учитывая то, что print - это действие awk по дефолту, то еще короче :)

$ printf "1\n2\n1\n" | awk '!t[$0]++'

2 darkk:

Цитата:

Короче. Но не аккуратно:
$ echo | awk ' ((2^53 + 1) % 2 == 0) { print "gotcha";}'
gotcha

А здесь нет проверки по модулю 2 :) Проблема могла бы быть только с переполнением целых чисел, а у вещественной арифметики все ок.

о. век живи, век rtfm Ж:-)
а этот приемчик с ++ я где то в перловых однострочниках подсмотрел

и читайте, к примеру, http://www.catonmat.net/tag/awk

А мне что-то влом писать то, что уже неоднократно разжёвано другими :)

Короче. Но не аккуратно:
$ echo | awk ' ((2^53 + 1) % 2 == 0) { print "gotcha";}'
gotcha

Отправить комментарий

Google Friend Connect (leave a quick comment)
loading...
Содержание этого поля является приватным и не предназначено к показу.