
foo
パターンの最初の発生からパターンの最後の発生までの行だけを取得するようにファイル(入力ストリーム)をどのように切り捨てますかbar
?
たとえば、次の入力を考えてみます。
A line
like
foo
this
foo
bar
something
something else
foo
bar
and
the
rest
次のような結果を期待しています。
foo
this
foo
bar
something
something else
foo
bar
答え1
sed -n '/foo/{:a;N;/^\n/s/^\n//;/bar/{p;s/.*//;};ba};'
sed パターンマッチングは/first/,/second/
1 行ずつ読みます。一部の行が一致する場合は、/first/
それを覚えて、/second/
そのパターンに最初に一致するものを探します。同時に、このモードで指定されたすべてのアクティビティが適用されます。その後、ファイルが終了するまでプロセスは引き続き開始されます。
それは私たちに必要なものではありません。最後に一致するパターンを見つける必要があります/second/
。だから私たちは最初の入り口だけが見える建物を建てます/foo/
。見つかるとループがa
始まります。一致バッファに新しい行を追加し、N
パターンと一致することを確認します/bar/
。もしそうなら、私たちはそれを印刷してマッチバッファを消去してからjanywayを使ってループの先頭にジャンプしますba
。
また、clean bufferを使用した後は、改行を削除する必要があります/^\n/s/^\n//
。より良い解決策があると確信しています。残念ながら、私はそれを考えていませんでした。
すべてが明確になることを願っています。
答え2
私は少しPerlを使ってみましょう。
cat <<EOF | perl -ne 'BEGIN { $/ = undef; } print $1 if(/(foo.*bar)/s)'
A line
like
foo
this
foo
bar
something
something else
foo
bar
and
the
rest
EOF
生産する
foo
this
foo
bar
something
something else
foo
bar
答え3
以下は、大量のメモリを必要としない2段階のGNU sedソリューションです。
< infile \
| sed -n '/foo/ { =; :a; z; N; /bar/=; ba }' \
| sed -n '1p; $p' \
| tr '\n' ' ' \
| sed 's/ /,/; s/ /p/' \
| sed -n -f - infile
説明する
- 最初の呼び出しはinfileを渡し、最初の発生とその後のすべての発生を
sed
見つけます。foo
bar
sed
sed
その後、これらのアドレスは2回の呼び出しと1回の呼び出しで構成される新しいスクリプトで構成されますtr
。 3番目の出力は括弧なしsed
です[start_address],[end_address]p
。- 最後に、呼び出しが再度
sed
転送され、infile
見つかったアドレスとその間のすべての内容が印刷されます。
答え4
別のアプローチは次のとおりですsed
。
sed '/foo/,$!d;H;/bar/!d;s/.*//;x;s/\n//' infile
/foo/,$
範囲内のすべての行(!
この範囲にない行は削除されますd
)をH
古いスペースに追加します。bar
次に、一致しない行を削除します。一致する行では、パターンスペースは空になり、eはx
予約済みスペースに変わり、パターンスペースの前の空白行は削除されます。
入力量が多く、bar
これがほとんど発生しない場合は、各行をパターンスペースにドラッグしてから毎回パターンスペースを確認するよりもはるかに高速ですbar
。
説明する:
sed '/foo/,$!d # delete line if not in this range
H # append to hold space
/bar/!d # if it doesn't match bar, delete
s/.*// # otherwise empty pattern space and
x # exchange hold buffer w. pattern space then
s/\n// # remove the leading newline
' infile
もちろん、これがファイルでメモリに収まる場合は、次のように簡単に実行できます。
ed -s infile<<'IN'
.t.
/foo/,?bar?p
q
IN
なぜならed
できる今後検索そして後ろ。
シェルがプロセス置換をサポートしている場合は、コマンド出力をテキストバッファに読み込むこともできます。
printf '%s\n' .t. /foo/,?bar?p q | ed -s <(your command)
そうでない場合は、次のようにしますgnu ed
。
printf '%s\n' .t. /foo/,?bar?p q | ed -s '!your command'