2015-05-26 5 views
1

Есть ли опция grep/sed, которая позволит мне сопоставить шаблон после сопоставления другого шаблона? Например: Входной файл (foo s являются переменными модели, начиная с 0 смешанных со случайными числами предшествуют # спереди): (., Например, foo2)Grepping второй шаблон после сопоставления первого шаблона

0foo1 
0foo2 
0foo3 
\#89888 
0foo4 
0foo5 
\#98980 
0foo6 

Поэтому, как только я пытаюсь найти переменную шаблона, я также хотите сопоставить другой шаблон (например, #number) из этого номера строки рисунка, в данном случае #89888.

Поэтому выход для переменной foo2 должен быть:

foo2 #89888 

Для переменной foo5:

foo5 #98980 

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

Я пробовал основной скрипт соответствия регулярному выражению с помощью tcl, который сначала будет искать foo*, а затем будет искать следующий немедленный #, но так как я работаю с очень большим файлом, для завершения потребуется несколько дней. Любая помощь приветствуется.

+1

Не могли бы вы использовать [pcregrep] (http://stackoverflow.com/tags/pcregrep/info), который имеет многострочную поддержку? – Biffen

ответ

2

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

perl -000 -nle 'm{(foo2).*(\#89888)}s and print join " ",$1,$2' file 

Переключатель -000 позволяет режим «хлебать», который сигнализирует Perl не разделить файл на куски, а скорее рассматривать его как одну большую строку. Модификатор s позволяет . соответствовать любому персонажу, включая новую строку.

0
#!/usr/bin/perl 

use strict; 
use warnings; 
use Data::Dumper; 

my (%matches, $recent_foo); 

while(<DATA>) 
{ 
    chomp; 
    ($matches{$recent_foo}) = $1 if m/(\\#\d+)/; 
    ($recent_foo) = $1 if m/(0foo\d+)/; 
} 

print Dumper(\%matches); 

__DATA__ 
0foo1 
0foo2 
0foo3 
\#89888 
0foo4 
0foo5 
\#98980 
0foo6 

./perl 
$VAR1 = { 
      '0foo5' => '\\#98980', 
      '0foo3' => '\\#89888' 
     }; 
0

Если то, что вы хотите 0foo1, 0foo2 и 0foo3 всем иметь одинаковое значение следующее будет делать:

#!/usr/bin/perl 

use strict; 
use warnings; 
use Data::Dumper; 

my (%matches, @recent_foo); 

while(<DATA>) 
{ 
    chomp; 
    if (/^\\#/) 
    { 
    @matches{@recent_foo} = ($') x @recent_foo; 
    undef @recent_foo; 
    } 
    elsif (/^0/) 
    { 
    push @recent_foo, $'; 
    } 
} 

print Dumper(\%matches); 

__DATA__ 
0foo1 
0foo2 
0foo3 
\#89888 
0foo4 
0foo5 
\#98980 
0foo6 

дает:

$VAR1 = { 
      'foo2' => '89888', 
      'foo1' => '89888', 
      'foo5' => '98980', 
      'foo3' => '89888', 
      'foo4' => '98980' 
     }; 
0
Var='foo2' 
sed "#n 
/${Var}/,/#[0-9]\{1,\}/ { 
    H 
    /#[0-9]\{1,\}/ !d 
    s/.*//;x 
    s/.//;s/\n.*\\n/ /p 
    q 
    }" YourFile 

Не ясно, как запрос. Это не займет первое вхождение вашего шаблона foo2 до первого #NUMBER удалите линию между ними и печатать как линию в 1, чем бросить курить (нет другого экстракта

раствора
0

Tcl. Процедура проходит в несколько более 3 микросекунд, так что вам понадобится очень больших файлов данных, чтобы они запускались в течение нескольких дней. Если используется более одного токена, используется первое совпадение (легко переписать процедуру для возврата всех совпадений).

set data { 
0foo1 
0foo2 
0foo3 
\#89888 
0foo4 
0foo5 
\#98980 
0foo6 
} 

proc find {data pattern} { 
    set idx [lsearch -regexp $data $pattern] 
    if {$idx >= 0} { 
     lrange $data $idx $idx+1 
    } 
} 

find $data 0foo3 
# -> 0foo3 #89888 
find $data 0f.*5 
# -> 0foo5 #98980 

Документация: if, lrange, lsearch, proc, set

0

СЭД

sed -n '/foo2/,/#[0-9]\+/ {s/^[[:space:]]*[0\\]//; p}' file | 
sed -n '1p; $p' | 
paste -s 
  • Первого SED печатает все строки между первым рисунком и 2, удалением опережающего пробелы и ведущие 0 или \.
  • Второе седло извлекает только первую и последнюю строки.
  • Команда paste печатает две строки в виде одной строки, разделенной вкладкой.

AWK

awk -v p1=foo5 ' 
    $0 ~ p1 {found = 1} 
    found && /#[0-9]+/ { sub(/^\\\/, ""); print p1, $0; exit } 
' file 

TCL

lassign $argv filename pattern1 
set found false 
set fid [open $filename r] 
while {[gets $fid line] != -1} { 
    if {[string match "*$pattern1*" $line]} { 
     set found true 
    } 
    if {$found && [regexp {#\d+} $line number]} { 
     puts "$pattern1 $number" 
     break 
    } 
} 
close $fid 

Затем

$ tclsh 2patt.tcl file foo4 
foo4 #98980 
0

Это то, что вы хотите?

$ awk -v tgt="foo2" 'index($0,tgt){f=1} f&&/#[0-9]/{print tgt, $0; exit}' file 
foo2 \#89888 

$ awk -v tgt="foo5" 'index($0,tgt){f=1} f&&/#[0-9]/{print tgt, $0; exit}' file 
foo5 \#98980 

Я использую index() выше, он ищет строки не регулярное выражение, и поэтому не мог заботиться меньше, что RE метасимволы в обув - все они просто буквальные символы в строке.

Непонятно из вашего вопроса, если вы хотите найти конкретное число после определенного foo или первого номера после foo2 или даже если вы хотите найти определенное значение foo или все «foo» или ...

Смежные вопросы