Сценарий сравнения двух файлов, сопоставление двух строк в любом месте строки

У вас 3 варианта:

  • запустить nmap от имени root
  • выполнить регулярное выражение фильтра на уровне системного журнала
  • изменить источник

1-й это рекомендуемый способ.

2
10.03.2017, 15:39
5 ответов

Это чистое решение на awk, которое работает для двух шаблонов на строку (разделенных пробелами) в файле шаблонов с операцией логического И:

awk 'NR==FNR{patts[$1]=$2;next}{for (i in patts) if (($0 ~ i) && ($0 ~ patts[i])) print}' patterns file

Обновление :
Для сопоставления слова вместо регулярного выражения вы можете оценить эту альтернативу:

awk 'NR==FNR{patts[$0]="\\<" $1 "\\>.*\\<" $2 "\\>|\\<" $2 "\\>.*\\<" $1 "\\>";next} \
{for (i in patts) if ($0 ~ patts[i]) print}' patterns file1   

Фактически он преобразует шаблон 833 7777 в
\ <833 \>. * \ <7777 \> | \ <7777 \>. * \ <833 \> , который выполняет сопоставление слов и имитирует также логическое И для двух шаблонов.

Это решение протестировано и не соответствует записям типа G 77771 2833

Обновление №2
Это обеспечит сопоставление слов, операцию логического И и печать для сопоставленных групп с разделительной строкой.

awk 'NR==FNR{patts[$0]="\\<" $1 "\\>.*\\<" $2 "\\>|\\<" $2 "\\>.*\\<" $1 "\\>";next} \
{for (i in patts) {if ($0 ~ patts[i]) !found[i]?found[i]=$0:found[i]=found[i] ORS $0}} \
END{for (k in found) {print found[k];print "-----"}}' patterns file1

#Output
A 833 0 0 0 0 7777 0 0 0 0
F 7777 833
-----
D illicit Jam fox 33333
-----                  
C the cow jumps over the 311 moon 2222
----- 

Онлайн-тестирование здесь.

PS: Из-за awk-способа работы с ассоциативными массивами мы не можем повлиять в секции END на печать найденного массива. Будет как-то «случайным».

1
27.01.2020, 22:03

Если известно, что в каждой строке файла file1 ровно две строки:

while read -ra elements; do
   grep "${elements[0]}" file2 | \
     grep "${elements[1]}" && \
     echo "----"
done < file1
1
27.01.2020, 22:03
perl -wMstrict -Mvars='*f2' -l -0777ane '
   if ( ! @ARGV ) {# this is File1 zone: slurped in $_
      while ( /^(\S+)\s+(\S+)$/mg ) {
         my $rx = qr/^(?=.*$1)(?=.*$2)/m; # AND matching of $1/$2
         pos($f2)=0;
         $f2 =~ /\G([^\n]+)/m and print $1 while $f2 =~ /$rx/mg;
         print "--- <Separator> ---" unless /\G\n\z/;
      }
   } else {# This is File2 zone: slurped whole in $f2
      $f2 = $_;
   }
' File2 File1 #<----- order is important here

Пояснение:

Мы должны помнить о порядке печати. здесь очень важно. Строки File2 печатаются в порядке, определяемом строками, которые должны быть найдены в File1. И после того, как каждая строка File1 сопоставляется с шаблоном File1, нам также нужна разделительная линия, независимо от того, было ли совпадение успешным или нет. Файлы прихлебываются, File2 => $ f2, и File обрабатывается как $ _ in

0
27.01.2020, 22:03

Здесь можно сделать трюк, который отлично работает в моих тестах:

$ awk -f <(sed 's/^\|$/\//g; s/ /\/ \&\& \//g' file1) file2
#Output
A 833 0 0 0 0 7777 0 0 0 0
C the cow jumps over the 311 moon 2222
D illicit Jam fox 33333
F 7777 833

Успех этого решения заключается в том, что мы преобразуем файл1 (паттерны) в формат awk /pattern1/ && /pattern2/{print} (print - действие по умолчанию, его можно опустить)

$ sed 's/^\|$/\//g; s/ /\/ \&\& \//g' file1
/311/ && /2222/
/833/ && /7777/
/Jam/ && /33333/

Вместо того, чтобы писать с помощью sed новый файл, мы передаем sed непосредственно в awk как файл, используя подстановку процесса.

Так команда :
awk -f <(sed 's/^\|$/\//g; s/ /\/ \&\& \//g' file1) file2 инструктирует awk прочитать программу из подзаголовка процесса и применить ее к файлу2.

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

PS: Это, конечно, должно быть чисто awk-решение.

0
27.01.2020, 22:03

Я бы сделал это в perl, потому что мне кажется, что так понятнее:

#!/usr/#bin/env perl
use strict;
use warnings;
use Data::Dumper;


my ( $pattern_file_name, $process_file_name ) = @ARGV; 

open ( my $patterns_file, '<', $pattern_file_name ) or die $!;
my @matches = map { [split] } <$patterns_file>;
close ( $patterns_file );

print "Using:\n";
print Dumper \@matches;

#my @matches = ( [ '311', '2222' ], [ '833', '7777' ], [ 'Jam', '33333' ] );

#read main file
my @results;
open  ( my $input, '<', $process_file_name ) or die $!; 

#iterate a line at a time. 
while ( my $line = <$input> ) {
 GROUP:
   for my $id ( 0 .. $#matches ) {
      #Check each set of expressions.
      foreach my $expression ( @{ $matches[$id] } ) { 
         #move to the next group if any don't match
         next GROUP unless $line =~ m/$expression/;
      }
      #didn't get skipped, so must have matched all. 
      push( @{ $results[$id] }, $line );
   }
}
print Dumper \@results;

print "\n$_\n" for @results;
close ( $input );
1
27.01.2020, 22:03

Теги

Похожие вопросы