次のコマンドは、特定のパターンの最初のオカレンスまで印刷しますが、それ以降のオカレンスは含まないことを知っています。
sed -n '1,/<pattern>/p' <file>
sed '/<pattern>/q' <file>
たとえば、次の行を含むファイルがあるとします。
this is a cow
this is a goat
this is a some fish
this is a fishie
this is a fish
this is a lion
this is a cat
次のように出力します。
$ sed '/fish/q' file
this is a cow
this is a goat
this is a some fish
$ sed -n '1,/fish/p' file
this is a cow
this is a goat
this is a some fish
最初の行から最後の項目を含む行まで出力を開始したいと思います。魚つまり、私が望む出力は次のようになります。
this is a cow
this is a goat
this is a some fish
this is a fishie
this is a fish
達成するために使用する方法は何ですかsed
?
答え1
この試み:
$ tac infile | sed -n '/fish/,$p' |tac
通常、sedコマンドで実行すると、最初の一致パターンから入力ファイルの終わりまですべての行が取得されます。
$ sed -n '/fish/,$p' file
this is a some fish
this is a fishie
this is a fish
this is a lion
this is a cat
だから私の解決策は次のとおりです。tac
入力ファイルからコマンドを実行すると、最後に一致したパターンが最初のパターンに変わります。結果を見るtac infile
:
$ tac infile
this is a cat
this is a lion
this is a fish
this is a fishie
this is a some fish
this is a goat
this is a cow
このtac
コマンドはコマンドと同じですcat
が、tac
ファイルを逆順に印刷します。
最初のsedコマンドを実行すると、まず入力ファイルの最後までパターンに一致するすべての行が得られます。良い:
$ tac infile | sed -n '/fish/,$p'
this is a fish
this is a fishie
this is a some fish
this is a goat
this is a cow
さて。終わりました。tac
行を元の順序に復元するには、コマンドを再実行するだけです。
$ tac infile | sed -n '/fish/,$p' |tac
this is a cow
this is a goat
this is a some fish
this is a fishie
this is a fish
完璧!
答え2
sed
これは非常に簡単です。 2つのバッファ間でわずかな調整が必要です。たとえば、
sed -n 'H;/fish/!d;$!n;x;p;G
' <<\INFILE
this is a cow
this is a goat
this is a some fish
this is a fishie
this is a fish
this is a lion
this is a cat
INFILE
このコマンドは、H
挿入された行文字の後の既存のスペースに各行を追加します\n
。一致し!
ない行は出力から/fish/
すぐに削除されます。これは私たちに線だけをd
残します。/fish/
したがって、この行はn
入力された拡張行で上書きされます。その後、パターンとh
既存のスペースが置き換えられます。H
結局、私たちはラインを古いものにしました。これで、パターン空間はH
前の空間であり、その逆も同様です。したがって、最後の行が一致したときに保存された内容をp
印刷します。/fish/
p
一致が見つかった場合にのみ印刷し、その間に中間行を保存するので、一致が最後に発生した場合にのみ到達します。ただし、一致する項目の間にできるだけ少ない量だけ保存します。x
バッファが変更されるたびにフラッシュされます。結果は次のとおりです。
this is a cow
this is a goat
this is a some fish
this is a fishie
this is a fish
私が時々魚をスキップすることを伝えてくれたDon Christyに感謝します。これで、フラッシュするたびにバッファが両端にプッシュされ、現在のパターンスペースを削除する前に毎回上書きされます。それは最初と最後の行の魚と私が知っている限り、それらの間のすべての行に適用されます。
私がやっているもう一つのことは、n
最後の行の延長コードを引くことです。これは絶対sed
禁忌です。これを手伝ってくれたドンにもう一度感謝します。
より徹底した例:
sed 'x;/./G;//!x;/fish/p;//s/.*//;x;d'
これが他の問題をよりよく解決することを願っています。h
パターン/既存のスペースはサイクルごとに変わります。これは、コマンドの最後に編集置換が追加されて空白行が発生するのをx
防ぐためです。s///
したがって、バッファが置き換えられ、バッファが空でないままになると、現在の行がここに追加され、その後に\n
ewline文字が追加されます。それ以外の場合は、追加の行がバッファから出力されます。それ以外の場合、バッファは再び交換され、h
前のスペースは現在のサイクル中は空のままになります。私が知る限り、このコマンドはすべての空白行と他のすべてを保持しますが、最後の一致で印刷を停止します。
私が経験した困難のいくつかは、通常、既存のh
スペースで発生します。これを効果的に使用する唯一の方法は、既存のラインと比較するためにラインサイクルの下 - 後ろ - にあることです。私が普段好むのはloopingですN;P;D
。おそらく、次のことを使ってこれを行うことができます。
sed -ne :n -e '/fish/!N;//p;//!bn'
入力拡張ラインをパターン空間に継続的にsed
追加し、ラベルに戻って再試行します。N
b
:n
魚現在までに設定された行と一致しません。ラインサイクルの終わりに内容をダンプし、新しいバッファで再起動する前に、一致するラインまたはp
ラインシーケンスのみを印刷します。fish
ここでは、意図的に最後の行をテストしません。最後の行が一致すると印刷されます。それ以外の-n
場合は、GNUの場合でも、sed
ループがファイルの最後の行をすべて終了するかどうかを決定します。
答え3
Sedより短いawkを使用することもできます。
awk ' /^fish/ { print $0 }' filename.txt
一部の人は次のように書くことができます:
awk ' /^fish/ { print $1 $2 $3 $4 $5 }' filename.txt
$n
列を表します。ショートカットは$0
行全体を表します。
答え4
Raku(以前のPerl_6)の使用
raku -e '$/.put if m/^ .* fish/ for lines.join("\n");'
入力例:
this is a cow
this is a goat
this is a some fish
this is a fishie
this is a fish
this is a lion
this is a cat
出力例:
this is a cow
this is a goat
this is a some fish
this is a fishie
this is a fish
上記の正規表現は1つの単語で終わり、その単語が行の最後の単語fish
である限りfish
正しく機能します。ただし、OPが全体をキャプチャしたい場合最後の行(例:fisherman
フルワードを返す)上記の正規表現マッチングをに変更しますm/^ .* fish .*? $$ /
。