위 행을 기준으로 행 선택

위 행을 기준으로 행 선택

활성 프로젝트의 이름을 선택하려는 프로젝트 목록이 있습니다.

item {
  status: "Active"
  properties {
    key_a: value
  }
  id: 42
  name: "Foo"
}
item {
  status: "Disabled"
  properties {
    key_b: value
  }
  id: 12
  name: "Bar"
}
item {
  status: "Active"
  id: 2
  name: "Baz"
}

캡처 그룹을 사용하여 이름을 추출할 수 있다는 것을 알고 있습니다 pcregrep.

$ cat list.txt | pcregrep -o1 -i '^  name: "(.*)"'
Foo
Bar
Baz

OR 표현식을 사용하면 중복된 상태 값과 이름 목록을 얻을 수도 있습니다.

$ cat list.txt | pcregrep -o2 -i '^  (status|name): "(.*)"'
Active
Foo
Disabled
Bar
Active
Baz

마지막으로 이전 행을 기반으로 목록의 이름을 필터링해야 합니다. 어떻게 해야 하나요?

최종 출력은 다음과 같아야 합니다.

Foo
Baz

답변1

변형만으로는 이 작업을 수행할 수 없다고 생각합니다 grep(물론 모르겠습니다 pcregrep). 노력하다 awk:

awk '/^ *status.*Active.$/ {ACT = 1} /^ *name:/ && ACT {gsub (/"/, "", $2); print $2; ACT = 0}' file
Foo
Baz

답변2

대부분의 무거운 작업은 에 의해 수행되었으므로 pcregrep이제 이 짧은 조각에 so/p를 전달할 수 있습니다 sed.

  sed -ne 'N;s/^Active\n//p'

이렇게 하면 sed기본 1행 대신 한 번에 2행을 볼 수 있습니다. 이 N명령은 개행 문자로 구분하여 다음 행을 패턴 공간에 붙여넣습니다 \n. 이제 sed만이 패턴 공간에서 활성 첫 번째 줄을 삭제할 수 있으며 나머지 패턴 공간이 인쇄됩니다. 조건부 인쇄입니다. 아무것도 하지 않고 -n패턴 공간이 자동으로 인쇄되지 않도록 하세요. HTH.

답변3

sed를 사용할 수도 있습니다.

sed '/status.*Active/,/name/!d;/name/!d;s/[^"]*"\([^"]*\)"/\1/' infile

답변4

또한 범위 연산자를 사용 하고 a로 제한하여 Perl블록 내의 boolean condition중첩된 괄호를 처리할 수도 있습니다.{}

일반적으로 Perlas 에 범위를 작성하면 정규식으로 시작 하고 정규식을 만족하는 줄에서 끝나는 블록이 선택 /re1/ ... /re2/됩니다 . 다음과 같이 말하여 이를 더욱 제한할 수 있습니다 .perl/re1//re2//re1/ ... /re2/ && $depth==0

perl이렇게 하면 깊이가 0인 추가 제약 조건이 있는 블록만 선택 됩니다 . 이 경우와 마찬가지로 }블록 종료는 발견으로 인해 깊이 카운트가 0으로 떨어질 때만 발생하며 OTW, 블록 축적도 이 표시를 지나 계속됩니다.

perl -lne '
    if ( /\{/ ... /\}/ && !$depth ) {
        if    ( /\{/ )                         { $depth = /^\h*item\h+\{\h*$/ ? 0 : ++$depth;     }
        elsif ( /\}/ )                         { print($name),undef($flag) if !$depth-- && $flag; }
        elsif ( /^\h*status:\h*"Active"\h*$/ ) { $flag = 1;                                       }
        elsif ( /^\h*name:\h/ )                { $name = (split /"/)[1];                          }
    }
' input.file

관련 정보