この質問は以下から来ています。 複数行のテキストファイルから中括弧の間のすべてのテキストを削除する方法は?(同じですが、入れ子の要件はありません)。
例:
This is {
{the multiline
text} file }
that wants
{ to {be
changed}
} anyway.
次のようにする必要があります。
This is
that wants
anyway.
これを実行するために使用できる一行のbashコマンド(awk、sed、perl、grep、cut、tr ...など)はありますか?
答え1
$ sed ':again;$!N;$!b again; :b; s/{[^{}]*}//g; t b' file3
This is
that wants
anyway.
説明する:
:again;$!N;$!b again
ファイル全体を読みます。
:again
ラベルです。N
次の行を読み、$!N
最後の行に達していない場合は、次の行を読みます。最後の行ではない場合は、ラベル$!b again
に分岐します。again
:b
これはラベルを定義します
b
。s/{[^{}]*}//g
これにより、テキストに内部括弧が含まれていない限り、中括弧内のテキストが削除されます。
t b
上記の代替コマンドで変更が発生した場合は、labelに戻ります
b
。このようにして、すべてのガシグループが削除されるまで置換コマンドを繰り返します。
答え2
パール方法:
$ perl -F"" -a00ne 'for (@F){$i++ if /{/; $i||print; $i-- if /}/}' file
This is
that wants
anyway
説明する
-a
-F
:配列で指定されたファイル区切り記号の自動分割をオンにします@F
。-F""
@F
:入力フィールド区切り文字を空白に設定します。これにより、各要素が入力文字の1つになります。-00
:「行」が連続する2つの改行で定義されている短絡モードをオンにします。これは、この場合、ファイル全体が1行として処理されることを意味します。ファイルに複数の段落があり、角かっこが複数の段落にまたがる可能性がある場合は、代わりにを使用してください-0777
。-ne
: 入力ファイルを読み込み、与えられたスクリプトを-e
各行に適用します。
スクリプト自体は実際には非常に簡単です。カウンタはaが表示されるたびに1ずつ増加し{
、表示されるたびに1ずつ減少します}
。これは、カウンタがゼロの場合は角括弧内にはなく、次のものを印刷する必要があることを意味します。
for (@F){}
:@F
行のすべての要素、すべての文字に対してこれを行います。$i++ if /{/;
:$i
キャラクターが1個なら1個追加{
$i||print;
:$i
設定されていない場合は印刷します(0は設定されていないと見なされます)。$i-- if /}/
:$i
文字が1の場合は1ずつ減少}