활성 프로젝트의 이름을 선택하려는 프로젝트 목록이 있습니다.
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
중첩된 괄호를 처리할 수도 있습니다.{}
일반적으로 Perl
as 에 범위를 작성하면 정규식으로 시작 하고 정규식을 만족하는 줄에서 끝나는 블록이 선택 /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