Удалить несколько повторяющихся строк из файла - PullRequest
0 голосов
/ 04 июля 2018

У меня есть скрипт Perl, запущенный в crontab, который генерирует файл, содержащий повторяющиеся записи, потому что при каждом запуске он перезаписывает ранее записанную информацию.

Я бы использовал sort -u файла, но я бы сделал это в конце файла сценария Perl.

Мой список

10/10/2017 00:01:39:000;Sagitter
10/11/2017 00:00:01:002;Lupus
10/12/2017 00:03:14:109;Leon
10/12/2017 00:09:00:459;Sagitter
10/13/2017 01:11:03:009;Lupus
12/13/2017 04:29:00:609;Ariet
10/11/2017 00:00:01:002;Lupus
10/12/2017 00:03:14:109;Leon
...

Мой код

#!/usr/bin/perl

# Libraries
use strict;
use warnings 'all';

%lines = ();

# Remove duplicate

open( TMP_GL_OUTPUT, '>', $OUTPUT_FILE ) or die $!;

while ( <TMP_GL_OUTPUT> ) {
    $lines{$_}++;
}

open( OUTFILE, '>', $TMPOUTPUT_FILE ) or die $!;
print OUTFILE keys %lines;
close( OUTFILE );

close( TMP_GL_OUTPUT );

Куда я иду не так? В оболочке он кажется короче, чем в Perl.

sort -u $TMPOUTPUT_FILE > $OUTPUT_FILE 

Как предложено пользователем ikegamy, я делаю следующее:

move $OUTPUT_FILE, $TMPOUTPUT_FILE; # Copy file
run [ 'sort', '-u', '--', $TMPOUTPUT_FILE ], '>', $OUTPUT_FILE; # Remove duplicate
unlink $TMPOUTPUT_FILE;

Ответы [ 3 ]

0 голосов
/ 04 июля 2018

Я думаю, вы спрашиваете, почему ваша Perl-программа длиннее, чем сценарий оболочки.

Прежде всего, ваш сценарий оболочки делает что-то совершенно иное, чем ваша Perl-программа.

  • Ваш сценарий оболочки выполняет программу и сохраняет ее в файле.
  • Ваша Perl-программа читает файл, обрабатывает прочитанные данные и сохраняет вывод в файл.

Perl эквивалентен

sort -u -- "$TMPOUTPUT_FILE" > "$OUTPUT_FILE"

есть

use IPC::Run qw( run );

run [ 'sort', '-u', '--', $TMPOUTPUT_FILE ], '>', $OUTPUT_FILE;

(Есть различия в обработке ошибок между этими двумя.)

Они не такие разные по длине.

Это вызывает вторую разницу. Оболочка специализируется на выполнении программ, но Perl - это язык общего назначения. Было бы удивительно, если бы это не было больше в Perl!

(Теперь попробуйте сравнить размер вашей Perl-программы с источником sort ...)

0 голосов
/ 05 июля 2018

List :: Util - основной модуль.

use List::Util 'uniq';

print for uniq <>
0 голосов
/ 04 июля 2018

Ваш код выглядит почти нормально.

Мое предложение только до chomp каждой строки, перед вами сохранить элемент в хэше.

Причина в том, что, например, последняя строка не завершена с \n может выглядеть так же, как одна из предыдущих строк, но без chomp предыдущая строка содержала бы окончание \n, тогда как последнее - нет.

Результат состоит в том, что обе эти строки будут различными ключами в хэше.

Сравните мой пример программы (работающей, представленной ниже) с вашей, есть никаких других существенных отличий, кроме чтения от __DATA__ и запись в консоль.

В моей программе для демонстрации я поставил 2 варианта распечатки, один со значениями ключа (количество повторений), а другой - печать только ключей. В вашей программе оставьте только вторую распечатку.

use strict; use warnings; use feature qw(say);

my %lines;
while(<DATA>) {
    chomp;
    $lines{$_}++;
}
while(my($key, $val) = each %lines) {
    printf "%-32s / %d\n", $key, $val;
}
say '========';
foreach my $key (keys %lines) {
    say $key;
}
__DATA__
10/10/2017 00:01:39:000;Sagitter
10/11/2017 00:00:01:002;Lupus
10/12/2017 00:03:14:109;Leon
10/12/2017 00:09:00:459;Sagitter
10/13/2017 01:11:03:009;Lupus
12/13/2017 04:29:00:609;Ariet
10/11/2017 00:00:01:002;Lupus
10/12/2017 00:03:14:109;Leon

Редактировать

Ваш код не присваивает имена $OUTPUT_FILE и $TMPOUTPUT_FILE, Вы даже не объявили эти переменные, но я предполагаю, что в вашем актуальном код ты это сделал.

Другая деталь заключается в том, что %lines должен предшествовать my, в противном случае при вводе use strict; компилятор выводит ошибку.

Редактировать 2

Существует более быстрое и короткое решение, чем у вас.

Вместо того, чтобы записывать строки в хеш и печатать их как в второй шаг, вы можете сделать это в цикле single :

  • Читать строку.
  • Проверьте, содержит ли хеш уже ключ, равный только что прочитанной строке.
  • Если нет, то:
    • записать строку в хеш, чтобы заблокировать распечатку, если только та же самая линия произошла снова,
    • печать строки.

Вы даже можете написать эту программу как однострочник Perl:

perl -lne"print if !$lines{$_}++" input.txt

Если вы запустите указанную выше команду из Windows cmd, она напечатает вывод на консоль. Если вы используете Linux, вместо двойных кавычек вы можете использовать апострофы.

Конечно, вы можете перенаправить вывод в любой файл, добавив > output.txt в вышеуказанная команда.

Код выполняется для каждой входной строки, разбитый на части из-за опции -l.

Если вам неизвестны какие-либо другие сведения, касающиеся однострочников Perl, поищите в Интернете.

...