私のファイルはfile.txt
次のとおりです。
[NamesA]
Andreas
Alex
[NamesB]
Bernd
Bruno
[NamesC]
Casper
[NamesD]
Doris
grep
次の3つの異なる出力を達成するために、これをbashスクリプトで使用または使用したいと思います。awk
出力
[NamesB] Bernd Bruno
出力
[NamesB] Bernd Bruno [NamesC] Casper
出力
[NamesD] Doris
私は試した:
grep -oP '\[NamesB\].*?' file.txt
ただし、[NamesB]
代わりに次のテキストブロックのみを取得します。私はテキストをすぐ後ろにインポートしましたが、新しい行にはインポートできませんでした。
それはすべてです。で始まる次の行を少なくともすべて得ることができれば[NamesB]
それはうまくいきません。
- したがって、1.の出力は、
[NamesB]
次の項目で始まり終わるすべての項目を印刷することで最も簡単になると想像できます[
。 - 2番は出力1番と似ていますが、2回実行されることを想像する
grep
こともできます。一度[NamesB]
、その後[NamesC]
[
しかし、以下がないので、3.ではこれはどのように機能しますか?そして、で始まる未知の次のブロックがあるかもしれません[
。
その後、コマンドはまたは[NamesB]
で始まるテキストの印刷を開始し、次に開く角かっこまたは[
ファイルの終わりで停止する必要があります。
PS:同様の質問を投稿して解決策を見つけましたが、全文行。この質問では、別の状況、つまり1行ではなくテキストブロックがあります。
答え1
印刷するレコードを選択するための要件は明確ではありませんが、おそらくこれがawkでやりたいことです。
出力1、オプション1(一度に1行ずつ読みます):
$ awk '/^\[/{f=(/^\[NamesB]/)} f' file.txt
[NamesB]
Bernd
Bruno
出力1、オプション2(一度に1つの複数行レコードを読む)
$ awk -v RS= -v ORS='\n\n' -F'\n' '$1 == "[NamesB]"' file.txt
[NamesB]
Bernd
Bruno
出力2、オプション1(NamesBレコードとそれに続くレコードを印刷):
$ awk -v RS= -v ORS='\n\n' -F'\n' '$1 == "[NamesB]"{c=2} c&&c--' file.txt
[NamesB]
Bernd
Bruno
[NamesC]
Casper
出力2、オプション2(入力位置に関係なくNamesBおよびNamesCレコードを印刷):
$ awk -v RS= -v ORS='\n\n' -F'\n' '$1 ~ /^\[Names[BC]]$/' file.txt
[NamesB]
Bernd
Bruno
[NamesC]
Casper
出力3、オプション1(NamesDレコード印刷):
$ awk -v RS= -v ORS='\n\n' -F'\n' '$1 == "[NamesD]"' file.txt
[NamesD]
Doris
出力3、オプション2(名前が何であれ、入力の4番目のレコードを印刷します):
$ awk -v RS= -v ORS='\n\n' -F'\n' 'NR == 4' file.txt
[NamesD]
Doris
また、以下に関連して:
少なくとも[NamesB]で始まる次の行をすべて取得できる場合
以下はトリックを行います。
$ awk -v RS= -v ORS='\n\n' -F'\n' '$1 == "[NamesB]"{f=1} f' file.txt
[NamesB]
Bernd
Bruno
[NamesC]
Casper
[NamesD]
Doris
もちろん、さまざまな基準に基づいて出力を生成するために他の多くのスクリプトを書くことができます。正しいスクリプトは、出力するチャンクを選択するときの要件によって異なります。
答え2
Raku(以前のPerl_6)の使用
~$ raku -e 'for slurp.split("\n\n") { .put if / \[ NamesA \] /};' file
#OR
~$ raku -e '.put if / \[ NamesA \] / for slurp.split("\n\n");' file
上記は、Perlシリーズのプログラミング言語であるRakuで書かれた答えです。つまり、ファイルは2つの連続した改行文字をslurp
使用して一度にメモリに書き込まれます。結果要素(レコード)は次のように繰り返されます。必須正規表現に一致する項目が見つかり、要素(レコード)が出力されます。split
\n\n
for
if
put
入力例:
[NamesA]
Andreas
Alex
[NamesB]
Bernd
Bruno
[NamesC]
Casper
[NamesD]
Doris
出力例:
[NamesA]
Andreas
Alex
|
正規表現マッチングでOR記号を使用すると、複数のレコードを返すことができます。戻り値を適切に分離するには、$_.put
または部分を書き換えて各レコードに末尾の改行文字を埋めることができます。.put
put "$_\n"
~$ raku -e 'put "$_\n" if / \[ NamesA | NamesB \] / for slurp.split("\n\n");' file
[NamesA]
Andreas
Alex
[NamesB]
Bernd
Bruno
注:正規表現マッチングはレコード内の任意の行にすることができます。最初の行を具体的に一致させるには、/^ \[ NamesA \] $$ /
ここでは^
文字列の始まりを意味し、行の$$
終わりを意味します。
答え3
以下を使用して、すべてのブロック(NamesAなど)を抽出できます。
$ awk '/^\[NamesA/{p=1; print; next} /^\[/{p=0}; p>0{print}' input_file
[NamesA]
Andreas
Alex
コードに示すように、ブロックヘッダーの最初の文字である[をエスケープする必要があります。
この1行を使用すると、必要に応じて出力の組み合わせを印刷できます。