GNU/Linux >> Linux の 問題 >  >> Linux

開始パターンと終了パターンの間の行を印刷しますが、終了パターンが存在しない場合は印刷しません

これは次のように実行できます:

$ sed -e '
    /BEGIN/,/END/!d
    H;/BEGIN/h;/END/!d;g
' inp

それがどのように機能するかは、行の開始/終了範囲に対して、それらをホールドスペースに保存することです。その後、END 行に達するまで削除します。その時点で、何が保持されているかを思い出します。 OTW、何も出力されません.HTH.


cat input |
sed '/\*\*\*\*\* BEGIN \*\*\*\*\*/,/\*\*\*\*\* END *\*\*\*\*/ p;d' | 
tac |
sed '/\*\*\*\*\* END \*\*\*\*\*/,/\*\*\*\*\* BEGIN *\*\*\*\*/ p;d' |
tac

tac を持つことで機能します sed になるように行を反転します 両方の順序で両方の区切り文字を見つけることができます。


pcregrep で :

pcregrep -M '(?s)BEGIN.*?END'

これは、BEGIN と END が同じ行にある場合にも機能しますが、次のような場合には機能しません:

BEGIN 1 END foo BEGIN 2
END

どこで pcregrep 最初の BEGIN 1 END をキャッチします 、しかし 2 番目のものではありません。

それらを処理するには、awk を使用します 、次のことができます:

awk '
  !inside {
    if (match($0, /^.*BEGIN/)) {
      inside = 1
      remembered = substr($0, 1, RLENGTH)
      $0 = substr($0, RLENGTH + 1)
    } else next
  }
  {
    if (match($0, /^.*END/)) {
      print remembered $0
      if (substr($0, RLENGTH+1) ~ /BEGIN/)
        remembered = ""
      else
        inside = 0
    } else
      remembered = remembered $0 ORS
  }'

次のような入力について:

a
BEGIN blah END BEGIN 1
2
END
b
BEGIN foo END
c
BEGIN
bar
END BEGIN
baz END
d
BEGIN
xxx

以下が得られます:

BEGIN blah END BEGIN 1
2
END
BEGIN foo END
BEGIN
bar
END BEGIN
baz END

どちらも、BEGIN から次の END までのすべてをメモリに格納する必要があります。そのため、最初の行に BEGIN が含まれているが END が含まれていない巨大なファイルがある場合、ファイル全体が無料でメモリに保存されます。

これを回避する唯一の方法は、ファイルを 2 回処理することですが、もちろん、入力が通常のファイル (たとえば、パイプではない) の場合にのみ実行できます。


Linux
  1. ファイルがまだ存在しない場合にのみファイルに行を追加する

  2. Tomcat がポート 8080 で動作するのに 80 で動作しないのはなぜですか?

  3. wc -l は、行末文字がない場合、ファイルの最後をカウントしません

  1. 2つのパターン間の(および除外する)行を印刷しますか?

  2. 2つのパターンの間(およびそれを含む)の線を印刷しますか?

  3. 1 で始まる行を grep しますが、10、11、100 などではありません。

  1. Linux:宛先ディレクトリが存在しない場合は、コピーして作成します

  2. Python の open() は、ファイルが存在しない場合、ファイルを作成しません。

  3. Androidエミュレーターが起動しない、avd