Grep для соответствия всем строкам patternfile (perl -e тоже хорошо) - PullRequest
4 голосов
/ 30 марта 2012

Я ищу простой / элегантный способ grep файла, чтобы каждая возвращаемая строка должна соответствовать каждой строке файла шаблона.

С входным файлом

acb
bc
ca
bac

И файлом шаблона

a
b
c

Команда должна вернуть

acb
bac

Я пытался сделать это с grep -f но возвращается, если он соответствует одному шаблону в файле (и не всем).Я также пробовал что-то с рекурсивным вызовом perl -ne (передняя строка файла шаблона, вызовите perl -ne для файла поиска и попытайтесь выполнить поиск на месте), но я не смог заставить синтаксический анализатор принять вызов perlот Perl, так что не уверен, что это возможно.

Я думал, что, возможно, есть более элегантный способ сделать это, поэтому я решил проверить.Спасибо!

=== ОБНОВЛЕНИЕ ===

Спасибо за ваши ответы до сих пор, извините, если я не ясно, но я надеялся только на результат в одну строку (создание сценариядля этого кажется слишком тяжелым, просто хотел что-то быстрое).Я думал об этом еще немного, и до сих пор придумал это:

perl -n -e 'chomp($_); print " | grep $_  "' pattern | xargs echo "cat input"

, который печатает

cat input | grep a | grep b | grep c

Эта строка - то, что я хочу выполнить, мне просто нужнокак-то выполнить это сейчас.Я пробовал дополнительный канал для eval

perl -n -e 'chomp($_); print " | grep $_  "' pattern | xargs echo "cat input" | eval

Хотя это дает сообщение:

xargs: echo: terminated by signal 13

Я не уверен, что это значит?

Ответы [ 6 ]

3 голосов
/ 30 марта 2012

В одну сторону, используя perl:

Содержимое input:

acb
bc
ca
bac

Содержимое pattern:

a
b
c

Содержимое script.pl:

use warnings;
use strict;

## Check arguments.
die qq[Usage: perl $0 <input-file> <pattern-file>\n] unless @ARGV == 2;

## Open files.
open my $pattern_fh, qq[<], pop @ARGV or die qq[ERROR: Cannot open pattern file: $!\n];
open my $input_fh, qq[<], pop @ARGV or die qq[ERROR: Cannot open input file: $!\n];

## Variable to save the regular expression.
my $str;

## Read patterns to match, and create a regex, with each string in a positive
## look-ahead.
while ( <$pattern_fh> ) { 
    chomp;
    $str .= qq[(?=.*$_)];
}

my $regex = qr/$str/;

## Read each line of data and test if the regex matches.
while ( <$input_fh> ) { 
    chomp;
    printf qq[%s\n], $_ if m/$regex/o;
}

Запустите его как:

perl script.pl input pattern

Со следующим выводом:

acb
bac
2 голосов
/ 30 марта 2012

Используя Perl, я предлагаю вам прочитать все шаблоны в массив и скомпилировать их. Затем вы можете прочитать входной файл, используя grep, чтобы убедиться, что все регулярные выражения совпадают.

код выглядит так

use strict;
use warnings;

open my $ptn, '<', 'pattern.txt' or die $!;
my @patterns = map { chomp(my $re = $_); qr/$re/; } grep /\S/, <$ptn>;

open my $in, '<', 'input.txt' or die $!;
while (my $line = <$in>) {
  print $line unless grep { $line !~ $_ } @patterns;
}

выход

acb
bac
1 голос
/ 30 марта 2012

Другой способ - прочитать все входные строки и затем начать фильтрацию по каждому шаблону:

#!/usr/bin/perl

use strict;
use warnings;

open my $in, '<', 'input.txt' or die $!;
my @matches = <$in>;
close $in;

open my $ptn, '<', 'pattern.txt' or die $!;
for my $pattern (<$ptn>) {
  chomp($pattern);
  @matches = grep(/$pattern/, @matches);
}
close $ptn;

print @matches;

выход

acb
bac
0 голосов
/ 24 февраля 2016

Вот решение только для grep:

#!/bin/sh
foo ()
{
        FIRST=1
        cat pattern.txt | while read line; do
        if [ $FIRST -eq 1 ]; then
                FIRST=0
                echo -n "grep \"$line\""
        else
                echo -n "$STRING | grep \"$line\""
            fi
        done
}
STRING=`foo`
eval "cat input.txt | $STRING"
0 голосов
/ 30 марта 2012

A bash (Linux) решение на основе

#!/bin/sh
INPUTFILE=input.txt #Your input file
PATTERNFILE=patterns.txt # file with patterns
# replace new line with '|' using awk
PATTERN=`awk 'NR==1{x=$0;next}NF{x=x"|"$0}END{print x}' "$PATTERNFILE"`
PATTERNCOUNT=`wc -l <"$PATTERNFILE"`
# build regex of style :(a|b|c){3,}
PATTERN="($PATTERN){$PATTERNCOUNT,}"

egrep "${PATTERN}" "${INPUTFILE}"
0 голосов
/ 30 марта 2012

Не grep и не один лайнер ...

MFILE=file.txt
PFILE=patterns
i=0
while read line; do
  let i++
  pattern=$(head -$i $PFILE | tail -1)
  if [[ $line =~ $pattern  ]]; then
    echo $line
  fi
  # (or use sed instead of bash regex:
  # echo $line | sed -n "/$pattern/p"
done < $MFILE
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...