テキスト ファイルをスキャンして、2 つのパターンの間にあるすべての単語を見つけるのに助けが必要です。たとえば、.sql ファイルがある場合、「from」と「where」の間のすべての単語をスキャンして検索する必要があります。grep は一度に 1 行しかスキャンできません。この要件に対して、使用するのに最適な UNIX スクリプトは何ですか? sed、awkにはこれらの機能がありますか? 例を挙げていただければ幸いです。
5 に答える
セッドはこれを持っています:
sed -n -e '/from/,/where/ p' file.sql
のある行と のある行の間のすべての行を出力from
しwhere
ます。
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 つのコマンドが実行されます。置換コマンドを使用して、s
from と where の間の部分 (from と where を含む) のみを抽出します。そのコマンドのp
サフィックスは行を出力します。delete コマンドは、パターン スペース (作業バッファー) をクリアし、次の行をロードしてスクリプトを再開します。
from
2 番目のコマンドは、次を含む行が見つかると一連のコマンド (中括弧でグループ化) の実行を開始します。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
これらのケースを処理するには、より多くのコードが必要です。
これが役立つことを願っています=)
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" に変更したのは、変数が実際に何であるかをより表現できるようにするためです。
これに使用でき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
grepだけを使用してこれを達成できました:
#> grep -A#### "start pattern" file | grep -B#### "end pattern"
問題は、同じ A オプションと B オプションに含める適切な行数を見つけなければならないことでした。お役に立てれば