2013-04-05 2 views
1

나는이 질문을 알고있다 How to find patterns across multiple lines using grep? 그러나 나는 나의 문제가 더 복잡하다고 생각한다. 그래서 도움이 필요해. 여러 줄 패턴 일치를 찾는 방법 (처음으로 일치해야 함)?

나는

boundary 
{ 
    inlet 
    { 
     type   fixedValue; 
     value   uniform (5 0 0); 
    } 

    outlet 
    { 
     type   inletOutlet; 
     inletValue  $internalField; 
     value   $internalField; 
    } 

    .... 
} 

내가 그렇게 inlet 경계 조건 fixedValue를 출력하는 스크립트를 쓰고 같은 사전 파일 BCFile하고 outlet 경계 조건 inletOutlet 있습니다.

cat BCFile | grep "type" | awk '{printf $2}' | tr -d ";"을 사용하면 키워드 type이 여러 번 발생하므로 작동하지 않습니다.

awk -v RS='}' '/inlet/ { print $4 }' BCFile을 사용하면 키워드도 inlet이 여러 번 발생하기 때문에 작동하지 않습니다.

은 내가 먼저 키워드 inlet를 검색 한 후 가장 가까운 {} 검색 패턴을 찾을 수있는 방법이 필요합니다.

누구나 스마트하게 수행하는 방법을 알고 있습니까?

+0

'플래그'변수가있는 awk 솔루션을 찾으십시오. 매주 여기에 여러 명이 나타납니다. 즉. '/ type/{t = 1};/value/{v = 1}; {t && v} 'file' (정확하게 맞지 않아서 코멘트로 올릴 수도 있습니다). 행운을 빕니다. – shellter

답변

2

당신은 우리가하지만 당신은 출력을 원하는 추측하고 게시 된 입력에 대한 예상 출력을 제공하지 않았기 때문에 어떻게 GNU에서 AWK에 대한 :

$ cat tst.awk 
BEGIN{ RS="\0" } 
{ 
    print "inlet:", gensub(/.*\yinlet\y[^}]*type\s+(\w+).*/,"\\1","") 
    print "outlet:", gensub(/.*\youtlet\y[^}]*type\s+(\w+).*/,"\\1","") 
} 
$ gawk -f tst.awk file 
inlet: fixedValue 
outlet: inletOutlet 

설명 :

RS="\0" 

= 레코드 구분 기호를 Null 문자열로 설정하면 awk가 전체 파일을 단일 레코드로 읽습니다. 문자를 제외한 모든 문자 단어 뒤에 inlet에 대한

gensub(/.*\yinlet\y[^}]*type\s+(\w+).*/,"\\1","") 

는 = 봐 } (그래서 당신은 중지 첫 번째 대신 파일의 마지막 }inlet} 전) 공백 다음에 다음 단어 type. 그 다음의 영숫자 문자열 (\w+)은 인쇄 할 단어이므로 기억하고 전체 레코드를 \\1에 저장된 문자열로 바꿉니다.

설정 RS="\0"gensub()은 모두 특정 gawk입니다.

+0

와우, 내 모자가 떨어져있어. 구문에 몇 가지 설명을 추가 하시겠습니까? :) – Daniel

+1

@ 대니얼 - 설명이 추가되었습니다. gawk 매뉴얼 (http://www.gnu.org/software/gawk/manual/gawk.html)도 참조하십시오. 이처럼 텍스트 파일 조작을 할 예정이라면 Arnold Robbins의 Effective Awk Programming 제 3 판을 읽어 보시기 바랍니다. –

+0

정말 고마워요. 스크립팅을 처음 접했을 때, 나는'sed'와'awk' 사이에서 선택하는데 큰 어려움을 겪었습니다. 어느 것이 더 강력하고 유연하며 좋은 보상 곡선을 가지고 있습니까? 감사합니다 – Daniel

1

Perl을 사용할 수 있습니까?

#!/usr/bin/env perl 

use strict; 
use warnings; 

my $filename = $ARGV[0]; 

open(my $f, '<', $filename) or die "Unable to open $filename: $!\n"; 
my $string = do { local($/); <$f> }; 
close($f); 

$string =~ /(inlet).*type\s*(\w+).*(outlet).*type\s*(\w+)/s; 
print "$1: $2\n$3: $4\n"; 
+0

고마워요! 그러나 쉘 스크립트는 이것을 할 수 없다. – Daniel

+0

UNIX 쉘은 도구를 호출하는 환경입니다. perl은 sed, grep, awk 등과 같은 도구입니다.유일한 차이점은 필자가 언급 한 다른 도구와 달리, Perl은 모든 UNIX 설치와 함께 제공되지 않는다는 것입니다. –

1

이 (GNU가 나오지도) 당신을 위해 일 수 있습니다

sed -rn '/^\s*(inlet|outlet)/,/^\s*}/!b;/type/s/.*\s(\S+);.*/\1/p' file 

당신이 '입구'중 하나를 사이에 '형'과 다음 '}'또는 '출구'과의 검색 범위를 좁힐 경우 다음 '}'이 전체 운동을 쉽게합니다.

+0

하하,이 무서워. – Daniel

관련 문제