一致する項目を含む最初の行の前のすべての行を削除しますか?

一致する項目を含む最初の行の前のすべての行を削除しますか?

正規表現文字列を使用して、一致を含む最初の行の前のすべての行をどのように削除できますか?たとえば、これをどのように変更できますか?

lost
load
linux
loan
linux

以下を入力してください:

linux
loan
linux

私は試した:

echo "lost
load
linux
loan
linux" | sed -e 's/.*^li.*$//g'

しかし、何も変更せずに次を返します。

lost
load
linux
loan
linux

一致するものがない場合は何も出力しないように動作したいと思います。

答え1

一方向POSIXly:

$ echo "lost
load
linux
loan
linux" | sed -e/linux/\{ -e:1 -en\;b1 -e\} -ed

またはより短く:

sed -n '/linux/,$p'

短く:

sed '/linux/,$!d'

短いバージョンより長いバージョンを好む理由を疑問に思う読者のために、長いバージョンはファイルの残りの部分に対してI / Oのみを実行しますが、範囲を使用すると2番目のアドレスがregexの場合パフォーマンスが低下し、正規表現は次のようになります。を試してください。必要以上に一致させます。

考慮する:

$ time seq 1000000 | sed -ne '/^1$/{' -e:1 -en\;b1 -e\}
=====
JOB sed -e '/^1$/,$d'
87%    cpu
0.11s real
0.10s user
0.00s sys

そして:

$ time seq 1000000 | sed -e '/^1$/,/1000000/d'
=====
JOB sed -e '/^1$/,/1000000/d'
96%    cpu
0.24s real
0.23s user
0.00s sys

2つのバージョンの違いを確認できます。複雑な正規表現の場合、これは大きな違いを生み出します。

答え2

これは明確に実行するのが簡単ですawk

echo "lost
load
linux
loan
linux" | awk '
    /^li/ { found = 1 }
    found { print }'

これはfound、任意に選択した自己記述名を持つ変数です。プログラムが正規表現に一致する入力行を検出すると設定されます。 (変数の初期デフォルト値は 0 または FALSE と機能的に同じ null です。) したがって、入力行は、パターンマッチングの前ではなく後に印刷され^liます。linuxパターンを見つけてフラグを設定するステートメントの後に条件付き印刷ステートメントがあるため、入力の3行目(最初の行)を印刷します。 4行目から印刷を開始するには後ろに最初のlinux行)2つのステートメントの順序を逆にするだけです。

正規表現に一致する入力行がない場合、フラグは設定されず、何も印刷されません。

前述したように、フラグ変数の名前は任意です。f必要に応じて、より短い名前(たとえば)を使用できます。そして{ print }基本動作なので省略しても良い。したがって、明確さが重要でない場合は、上記の内容を次のように短縮できます。

echo "lost
load
linux
loan
linux" | awk '/^li/{f=1}f'

答え3

他の2つのawkソリューション:

両方とも、found最初の正規表現の一致を表示するときにフラグを設定し、そのフラグが設定されている場合に印刷します。

echo "lost
load
linux
loan
linux" | awk 'BEGIN {found = 0} {if (found || $0 ~ /linux/) {found = 1; print}}'

これは少し長いですfoundが、フラグをリセットしません。

echo "lost
load
linux
loan
linux" | awk 'BEGIN {found = 0} {if (found) {print} else if ($0 ~ /linux/) {found = 1; print}}'

答え4

あなたはそれを使用することができます前任者バッチモードでファイルを直接編集します。 (実際にファイルを変更する前に出力ファイルが何であるかを確認したい場合は。に置き換えてくださいx%p

printf '%s\n' 'a' 'linux' '.' '1,/linux/-1d' '$d' 'x' | ex -s file
  1. a、、linuxwriteは.最後に1行を追加します。linux
  2. 1,/linux/-1d間隔[ファイルの最初の行、最初の前の最初の行]linuxから行を削除します。
  3. $d手順1で手動で挿入した行を削除します。
  4. x変更を作成して終了します。

より直接的なアプローチ(参照:編集履歴の最初のバージョン) 一致する項目が存在しない場合、ファイルは変更されていません。これにより、必要に応じてファイルが消去されます(したがって、奇妙なステップ1)。

$ cat file1
lost
load
linux
loan
linux
$ printf '%s\n' a linux . 1,/linux/-1d '$d' x | ex -s file1
$ cat file1
linux
loan
linux
$ cat file2
lost
load
loan
$ printf '%s\n' a linux . 1,/linux/-1d '$d' x | ex -s file2
$ cat file2  #file2 is empty

関連情報