awk:コードブロックを分離し、存在する場合は複数のブロックを繰り返します。

awk:コードブロックを分離し、存在する場合は複数のブロックを繰り返します。

awk †は""のn番目の反復を見つけて、次の" {"文字まで}すべてを返すことはできますか?

[編集:はい... Ed Mortonのソリューションは一番下にあります。]

†私はいつもawkがその仕事に適したツールだと思いました。他のアイデアも大歓迎です。

何百ものファイルからテキストブロックを分離する必要があります。一部のファイルにはブロックが1つしかありませんが、他のファイルには何十ものファイルが含まれています。

サンプル:

$ cat samp2.txt
//////////////////////////////////
// North Carolina office
// satellite branch
//////////////////////////////////
   {
   first   "John"
   last    "Doe"
   address "163 Main Street"
   age     "25"
   gender  "male"
   }

>現在のチャンクを一時ファイルに入れて、スクリプトが次のチャンクを処理する前にそれを操作できるようにすることをお勧めします。それにもかかわらず、それらは別々のファイルで終了します。

私はn番目の一致を見つけるためにawkにインデックスを提供することが可能だと思います。 Bashスクリプトはループと反復を管理できます。

私は近い

$ awk '/\{/{flag=1;next}/\}/{flag=0}flag' samp2.txt 
   first   "John"
   last    "Doe"
   address "163 Main Street"
   age     "25"
   gender  "male"

ただし、上記の操作はファイル全体に対して実行されるため、複数のブロックを含むファイル(以下のような)では機能しません。ファイルにいくつのブロックがあるかに関係なく各ブロックは分離されています。別途処理する必要があります。

一部のファイルにはコメントが含まれていますが、多くのファイルにはコメントが含まれていません。標準はありません。私はそれらを破棄しましたが、矛盾のためにそのコメントを使用して私たちの場所を追跡することはできませんでした。与えられた唯一のものは中括弧(および行区切り文字)です。

テキストは常に改行で区切られますが、ブロック間に常に空白行があるわけではありません。データのペアはさまざまなので、これは単純なgrep 5 lines and proceed解決策ではありません。

$ cat samp3.txt 
//GROUP1
{
first       "John"
address     "124 Main Street"
last    "Jones"
special     "supervisor"
age "35"
gender      "male"
}

//The fourth group
{
first       "John"
address     "125 Main Street"
last    "Jacob"
age "30"
gender      "male"
}
{
first       "John"
address     "523 Main Street"
last    "Jingle"
age "40"
gender      "male"
}

上記のawkの説明は、すべてのグループを介して1つの大きな段落にマージされます。

$ awk '/\{/{flag=1;next}/\}/{flag=0}flag' samp3.txt
first       "John"
address     "124 Main Street"
last    "Jones"
special     "supervisor"
age "35"
gender      "male"
first       "John"
address     "125 Main Street"
last    "Jacob"
age "30"
gender      "male"
first       "John"
address     "523 Main Street"
last    "Jingle"
age "40"
gender      "male"

{次のようにawkにn番目の ""を見つけて、n番目の}""を個別にダンプするように指示する必要があります。

first       "John"
address     "124 Main Street"
last    "Jones"
special     "supervisor"
age "35"
gender      "male"
 (awk exits, bash script does its thing)

first       "John"
address     "125 Main Street"
last    "Jacob"
age "30"
gender      "male"
 (awk exits, bash script does its thing)

first       "John"
address     "523 Main Street"
last    "Jingle"
age "40"
gender      "male"
 (awk exits, bash script does its thing)

 [etc]

意図は、{ .+ }貪欲ではないn番目の正規表現の一致に似ています。
これでよりスマートなPerlソリューションがありますか?

ティア。

このコードは私が必要とするものを取得します。 Ed Mortonの回答に基づいて修正されました。

awk -v n=$LoopVariable -v RS='}' 'NR==n{gsub(/.*\{\r?\n|\n$/,""); print}' $SourceFile

編集:入力は私が必要とする質問と質問を分離するのに本当に役立ちました。ありがとうございます。


見つけました。 一部 SEの問題それとても似ているようです。しかし、ここに私の解決策が含まれていれば、接続を見るのに十分なawkについて十分にはわかりません。

ベストアンサー1

あなたの質問で予想される出力を見ていなかったので、私はわかりませんが、Can awk † find the nth iteration of a "{" and return everything up to the next "}" character?これがあなたが望むものであると言いました(awkを使用して入力の他の場所には現れないと仮定してください)}{

$ awk -v n=2 -v RS='}' 'NR==n{gsub(/.*\{\n|\n$/,""); print}' samp3.txt
first       "John"
address     "125 Main Street"
last    "Jacob"
age "30"
gender      "male"

シェルループから呼び出すには:

$ for i in {1..3}; do
    awk -v n="$i" -v RS='}' 'NR==n{gsub(/.*\{\n|\n$/,""); print}' samp3.txt
    echo "-----"
done
first       "John"
address     "124 Main Street"
last    "Jones"
special     "supervisor"
age "35"
gender      "male"
-----
first       "John"
address     "125 Main Street"
last    "Jacob"
age "30"
gender      "male"
-----
first       "John"
address     "523 Main Street"
last    "Jingle"
age "40"
gender      "male"
-----

しかし、ループ内でawkを何度も呼び出すよりも望むことを達成するより良い方法はほとんど確実です。たとえば、awk を一度呼び出して終端子を持つ各チャンクを印刷し、さらに}処理するためにシェル配列に読み込みます。

$ readarray -d '}' -t arr < <(awk 'BEGIN{RS=ORS="}"} {gsub(/.*\{\n|\n$/,"")} $0~/[^[:space:]]/' samp3.txt)
$ for i in "${arr[@]}"; do printf '%s\n' "$i"; echo "-----"; done
first       "John"
address     "124 Main Street"
last    "Jones"
special     "supervisor"
age "35"
gender      "male"
-----
first       "John"
address     "125 Main Street"
last    "Jacob"
age "30"
gender      "male"
-----
first       "John"
address     "523 Main Street"
last    "Jingle"
age "40"
gender      "male"
-----

ただし、実際にシェルループで実行するすべての操作は、awkへの単一の呼び出しで実行する必要があります。

おすすめ記事