10

テキスト ファイルをスキャンして、2 つのパターンの間にあるすべての単語を見つけるのに助けが必要です。たとえば、.sql ファイルがある場合、「from」と「where」の間のすべての単語をスキャンして検索する必要があります。grep は一度に 1 行しかスキャンできません。この要件に対して、使用するのに最適な UNIX スクリプトは何ですか? sed、awkにはこれらの機能がありますか? 例を挙げていただければ幸いです。

4

5 に答える 5

23

セッドはこれを持っています:

sed -n -e '/from/,/where/ p' file.sql

のある行と のある行の間のすべての行を出力fromwhereます。

from と where の両方を含む行を含めることができるものの場合:

#!/bin/sed -nf

/from.*where/ {
    s/.*\(from.*where\).*/\1/p
    d
}
/from/ {
    : next
    N
    /where/ {
        s/^[^\n]*\(from.*where\)[^\n]*/\1/p
        d
    }
    $! b next
}

これ (sed スクリプトとして記述) はもう少し複雑なので、詳細を説明しようと思います。

from最初の行は、 aと a の両方を含む行で実行されwhereます。行がそのパターンに一致する場合、2 つのコマンドが実行されます。置換コマンドを使用して、sfrom と where の間の部分 (from と where を含む) のみを抽出します。そのコマンドのpサフィックスは行を出力します。delete コマンドは、パターン スペース (作業バッファー) をクリアし、次の行をロードしてスクリプトを再開します。

from2 番目のコマンドは、次を含む行が見つかると一連のコマンド (中括弧でグループ化) の実行を開始します。where基本的に、コマンドはループを形成し、a を含む行が見つかるまで、または最後の行に到達するまで、入力からパターン スペースに行を追加し続けます。

:コマンド」は、必要なときに「ジャンプ」できるスクリプト内のマーカーであるラベルを作成します。このNコマンドは、入力から 1 行を読み取り、それをパターン スペースに追加します (行を改行文字で区切ります)。

awhereが見つかったら、パターン スペースの内容を出力できますが、最初に代替コマンドでそれをきれいにする必要があります。これは以前に使用されたものと似ていますが、先頭と末尾.*[^\n]*に置き換えます。これにより、sed は非改行文字のみに一致するようになり、最初の行の from と最後の行の where に効果的に一致します。次に、dコマンドはパターン スペースをクリアし、次の行でスクリプトを再開します。

このbコマンドは、ラベル (この場合は label ) にジャンプしますnext。ただし、$!アドレスには、最後の行で実行してはならないことが示されているため、ループから抜け出すことができます。このようにループを離れると、それぞれwhereの が見つからないため、印刷したくない場合があります。

ただし、これにはいくつかの欠点があることに注意してください。次の場合は、期待どおりに処理されません。

from ... where ... from

from ... from
where

from
where ... where

from
from
where
where

これらのケースを処理するには、より多くのコードが必要です。

これが役立つことを願っています=)

于 2012-10-16T15:42:02.920 に答える
2

GNU awk を使用すると、RS を RE に設定できます。

gawk -v RS='[[:space:]]+' '
   /where/ { found=0 }
   found   {  print  }
   /from/  { found=1 }
' file

上記は、「from」と「where」を印刷したくないことを前提としており、必要に応じて行を移動してください。

次のイディオムは、一致する特定のパターンを指定してレコードの範囲を選択する方法を説明しています。

a) いくつかのパターンからすべてのレコードを印刷します。

awk '/pattern/{f=1}f' file

b) いくつかのパターンの後にすべてのレコードを印刷します。

awk 'f;/pattern/{f=1}' file

c) いくつかのパターンの後に N 番目のレコードを出力します。

awk 'c&&!--c;/pattern/{c=N}' file

d) いくつかのパターンの後、N 番目のレコードを除くすべてのレコードを出力します。

awk 'c&&!--c{next}/pattern/{c=N}1' file

e) いくつかのパターンの後に N レコードを出力します。

awk 'c&&c--;/pattern/{c=N}' file

f) いくつかのパターンの後に N レコードを除くすべてのレコードを出力します。

awk 'c&&c--{next}/pattern/{c=N}1' file

g) いくつかのパターンから N レコードを出力します。

awk '/pattern/{c=N}c&&c--' file

変数名を "found" の "f" から "count" の "c" に変更したのは、変数が実際に何であるかをより表現できるようにするためです。

于 2012-10-16T16:09:46.330 に答える
1

これに使用できedます。正規表現範囲の正と負のオフセットが許可されます。入力が次の場合:

seq 10 | tee > infile
1
2
3
4
5
6
7
8
9
10

コマンドを次の場所にパイプしedます。

<<< /3/,/6/p | ed -s infile

つまり3、 とを含む行の間のすべてを出力し6ます。

結果:

3
4
5
6

両端にもう 1 行追加するには:

<<< /3/-1,/5/+1p | ed -s infile

結果:

2
3
4
5
6
7

またはその逆:

<<< /3/+1,/6/-1p | ed -s infile

結果:

4
5
于 2012-10-17T00:34:27.230 に答える
1

grepだけを使用してこれを達成できました:

#> grep -A#### "start pattern" file | grep -B#### "end pattern"

問題は、同じ A オプションと B オプションに含める適切な行数を見つけなければならないことでした。お役に立てれば

于 2014-02-26T20:25:37.983 に答える