sedを使用して、最後のパターンの発生と空白行の間のテキストを印刷したいと思います。たとえば、次のファイルから:
$ cat file
pattern
1
2
3
pattern
4
5
pattern
6
7
8
9
10
11
ただ印刷したい
6
7
8
9
私sed '/pattern/{:1;$!{/^$/!{N;b1};h}};${x;p};d' file
から試してみるここしかし、うまくいきません。
編集:これはほとんど動作します:
$ sed -n -e '/pattern/ {n; :a; $!{/\n$/!{N;ba};h} }; $ { x;p }' file
6
7
8
9
最後に空白行を削除する方法は?
Edit2:これはうまくいく解決策です。
$sed '/pattern/{:1;$!{/\n$/!{N;b1};h}};${x;s/pattern\n//;s/\n$//;p};d' file
6
7
8
9
Edit3: これは良いです:
$sed '/pattern/{:1;$!{/\n$/!{N;b1};s///;h}};${x;s/pattern\n//;p};d' file
答え1
ストリームエディタを使用してsed
パターンレコードを検出し、そこから行をスキップし、次の空行が見つかるまで繰り返します。それまではパターン空間のレコードが蓄積され、ループ後はホールド空間の内容をパターン空間の内容で上書きします。これはすべてのパターン...空のラインブロックに対して再び発生します。ファイルの末尾で保留内容を検索し、空でない場合は印刷します。
$ sed -ne '
/pattern/{
$d;n
:loop
s/\n$//;tdone
$bdone;N
bloop
:done
x
}
${x;/./p;}
' file
6
7
8
9
最大。ラインエディタはこの範囲のような問題に自然に適しています。編集する
ed -s file <<\eof
a
.
?pattern?+1;/^$/-1p
Q
eof
GNU sedエディタを使用する別の方法は、範囲演算子を使用して予約済みスペースのブロックを収集することです。
sed -e '
/pattern/,/^$/!ba
/./!ba
H;/pattern/{z;x;}
:a
$!d;x;s/.//
' file
私たちはSlurpモードでGNU sedエディタを使用することができ、パターンの最後のインスタンスに到達するために正規表現の欲張りな特性を使用できます。
sed -Ez '
s/.*pattern\n(([^\n]+\n)+)(\n.*)?/\1/
' file
以下はPerlの範囲演算子に対応するsedです。 Array@Aはブロックラインの集水ゾーンとして機能します。
perl -ne 'next unless
my $e = /pattern/ .. /^$/;
@A = $e == 1 ? ()
: /./ ? (@A, $_)
: @A;
}{print @A;
' file
答え2
awk '/pattern/,/^$/ { arr[NR]=$0; if (/pattern/) line1=NR; if (/^$/) line2=NR}END{ if (line1) for(i=++line1;i<line2;i++) print arr[i]}' file
/pattern/,/^$/
パターンと空白行の間に線が生じます。
次に、if (/pattern/) line1=NR
パターンが見つかった最後の行のレコード番号を提供します。if (/^$/) line2=NR
最後の空行の行番号を提供しますパターンを見つけた後。
最後に、2つのレコード間のforループは予想される出力を返します。
パターンと次の空行の間に2行がない、パターンがファイルにない、またはパターンの外に空行がない場合、この操作は失敗します。 (からインポートここ)
答え3
私の考えでは、以前のソリューションこの問題を解決するために拡張することもできます。
printf '%s\n' '?pattern?+1' '. +1,/^$/ -1 p' | ed -s file
これにより、次のアドレスに2つのコマンドが送信されますed
。
?pattern?+1
- ファイルの末尾から戻るパターンを検索し、一致するものを1行進めると、その行が印刷されます。. +1,/^$/ -1 p
- 次の行(現在の行+ 1)から次の空の行()の前の行まで/^$/ -1
印刷します。
pattern
そのジョブと次の空行の間に2行がない、pattern
ファイルにない、または後に空行がない場合、pattern
この操作は失敗します。
答え4
これはおそらく最も簡単ですawk
。
$ awk -v RS='' -F '\n' '$1 ~ /pattern/ { hold = $0 } END { if (hold != "") print hold }' file | sed 1d
6
7
8
9
awk
RS
これは、「短絡読み取りモード」に入る空の入力レコード区切り文字で使用されます。awk
つまり、一度に全体の段落を取得します$0
。これは、段落の最初の行と同様に、-F '\n'
段落の各行が別々のフィールドになるという意味でも使用されます。$1
このコードは、正規表現が段落pattern
の最初の行と一致するかどうかをテストします。その場合、変数は段落を保持しますhold
。
最後に空でhold
ない場合は印刷してください。
sed
出力の最初の行(一致する行pattern
)を削除するために使用されます。
$pattern
静的モードの代わりにシェル変数を使用するには、次のようにします。
pattern=$pattern awk -v RS='' -F '\n' '$1 ~ ENVIRON["pattern"] { hold = $0 } END { if (hold != "") print hold }' file | sed 1d