Попытка получить повторяющиеся серийные номера, повторяющиеся более трех раз из этого списка, с помощью команды perl или awk - PullRequest
1 голос
/ 14 февраля 2020

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

Time     serial no's     oui   product class
23:38:17 G1A114071803436|D4A928|FiOS-Gen4
23:38:18 G1A117072200565|D4A928|FiOS-Gen4
22:38:17 G1A114071803436|D4A928|FiOS-Gen4
23:38:17 G1A114071803436|D4A928|FiOS-Gen4
23:38:18 G1A117072200565|D4A928|FiOS-Gen4
23:07:51 G1A114080901301|D4A928|FiOS-Gen4
23:10:36 G1A114080901301|D4A928|FiOS-Gen4
20:11:51 G1A114080901301|D4A928|FiOS-Gen4

Так что, если я возвращаю вывод, он должен выглядеть примерно так:

Только дублированные серийные номера *

должны быть:

G1A114080901301|D4A928|FiOS-Gen4
G1A114071803436|D4A928|FiOS-Gen4

(поскольку эти серийные номера повторяются только более двух раз)

Команды, которые я использовал :

sort  sed2file.csv | uniq -id > sortedfile.csv
perl -ne 'print if $a{$_}++' filename

Ответы [ 5 ]

1 голос
/ 14 февраля 2020

Попробуйте tail плюс однострочник perl, например:

tail -n +2 input_file | \
perl -F'/[|]|\s+/' -lane '
print join( q{|}, @F[1..$#F]) if $seen{ $F[1] }++ == 2;'

Печать:

G1A114071803436|D4A928|FiOS-Gen4
G1A114080901301|D4A928|FiOS-Gen4

Здесь tail -n +2 пропускает первую строку (заголовок) , Это необязательно, но я предпочитаю его для надежного, чистого кода и результатов ниже по течению.

Однострочный perl использует следующие флаги командной строки:
-e: говорит Perl искать код в строке, а не в файле.
-n : l oop по одной строке за раз, присваивая ей значение $_ по умолчанию.
-l: удалите разделитель строки ввода ("\n" в * NIX по умолчанию) перед выполнением кода в и добавьте его, когда print -ing.
-a: разбить $_ на массив @F на регулярное выражение, указанное в опции -F.
-F'/[|]|\s+/': при разбиении на @F, используйте это регулярное выражение: труба (|) или один или несколько пробелов (\s+).

Код сохраняет количество раз, когда 2-е поле (серийный номер) было замечено. Для этого он использует $seen{ $F[1] }++. Обратите внимание, что массивы в Perl имеют индекс 0.

Когда счет равен 2 (то есть, когда он становится равным 3 после автоинкремента), выполняется print.

Если вы хотите напечатать всю строку, просто используйте print без аргументов, что совпадает с print $_. Однако здесь все столбцы, кроме первого (индексы: 1..$#F), объединяются в | и печатаются.

1 голос
/ 14 февраля 2020

Пример кода, как этого можно достичь в perl. Посмотрите, соответствует ли это вашей цели.

use strict;
use warnings;
use feature 'say';

use Data::Dumper;

my $debug = 0;                      # debug flag

my %data;                           # data storage
my $num_duplicates = 3;             # treshold for duplicates

for (<DATA>) {                      # walk through data
    next if /Time/;                 # skip header
    chomp;                          # snip \n
    my($time,$serial) = split ' ';  # get time and serial
    $data{$serial}++;               # count duplicates
}

say Dumper(\%data) if $debug;       # look into what we collected

for my $k ( sort keys %data ) {     # look for treshold
    say $k if $data{$k} >= $num_duplicates; 
}

__DATA__
Time     serial no's     oui   product class
23:38:17 G1A114071803436|D4A928|FiOS-Gen4
23:38:18 G1A117072200565|D4A928|FiOS-Gen4
22:38:17 G1A114071803436|D4A928|FiOS-Gen4
23:38:17 G1A114071803436|D4A928|FiOS-Gen4
23:38:18 G1A117072200565|D4A928|FiOS-Gen4
23:07:51 G1A114080901301|D4A928|FiOS-Gen4
23:10:36 G1A114080901301|D4A928|FiOS-Gen4
20:11:51 G1A114080901301|D4A928|FiOS-Gen4

Вывод

G1A114071803436|D4A928|FiOS-Gen4
G1A114080901301|D4A928|FiOS-Gen4
1 голос
/ 14 февраля 2020

awk решение:

$ awk 'NR > 1 { split($2, cols, "[|]"); serials[cols[1]]++; rows[cols[1]]=$2 }
       END { for (s in serials) if (serials[s] >= 3) print rows[s] }' input.txt
G1A114080901301|D4A928|FiOS-Gen4
G1A114071803436|D4A928|FiOS-Gen4

Отслеживает количество раз, которое появляется каждый серийный номер, и после обработки всего файла печатает только те, которые появляются 3 или более раз, без учета временных отметок. Обратите внимание, что при этом соответствующие записи будут напечатаны в произвольном порядке.

0 голосов
/ 14 февраля 2020

Perl решение командной строки (при условии, что ваши данные находятся в файле с именем data.txt):

perl -anE 'BEGIN { <> } \
           END { for (keys %id) { say $_ if $id{$_} > 2 } } \
           $id{$F[1]}++' data.txt 

Я разделил код на три строки (что, честно говоря, немного большой для программы командной строки). Я надеюсь, что это облегчит следовать.

-anE: Опции командной строки. -a Авторазделение ввода в @F, -n зацикливает ввод строки за раз, -E выполняет следующий код.

BEGIN { <> }: блок, который выполняется перед началом чтения входного файла. Просто читает строку из файла (чтобы пропустить заголовки).

END { ... }: блок, выполненный после прочтения всего входного файла.

for (keys %id) { ... }: выполнить это l oop для каждого ключа в %id га sh.

say $_ if $id{$_} > 2: если мы видели более двух строк, напечатайте ключ.

$id{$F[1]}++: Это весь код, который фактически выполняется для каждой строки во входном файле. Входная запись разбивается на пробелы и сохраняется в @F. Поэтому $F[1] - это второе поле в записи (интересующий вас идентификатор), и мы увеличиваем значение в %id га sh, используя этот идентификатор в качестве ключа.

0 голосов
/ 14 февраля 2020

Вы можете сделать это тривиально с помощью awk, например,

awk '{seen[$2]++; if(seen[$2]==3) print $2}' serials.txt

Вывод:

G1A114071803436|D4A928|FiOS-Gen4
G1A114080901301|D4A928|FiOS-Gen4

Над массивом seen, индексируемым вторым полем, содержащим число раз serial|oui|product class видно. Когда он равен 3, просто выведите этот набор значений (он не будет печататься до тех пор, пока счетчик не станет равным 3, а затем проигнорирует вхождения из-за используемого ==)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...