上記の行に基づいて行を選択

上記の行に基づいて行を選択

アクティブなプロジェクトの名前を選択したいプロジェクトのリストがあります。

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

関連情報