アクティブなプロジェクトの名前を選択したいプロジェクトのリストがあります。
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の追加制約を持つブロックのみが選択されます。この場合と同様に、}
ブロック出口は、ディスカバリーによって深さカウントがゼロに低下した場合にのみ発生し、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