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

正規表現とgrep:データフローとビルディングブロック

正規表現の紹介 、私はそれらが何であるか、そしてなぜそれらが有用であるかをカバーしました。それでは、それらがどのように作成されるかを詳しく見ていきましょう。 GNU grep は私が最もよく使用するツールの1つであり(正規表現の多かれ少なかれ標準化された実装を提供します)、この記事の基礎としてその式のセットを使用します。次に、 sedを見ていきます。 (正規表現を使用する別のツール)後の記事で。

正規表現のすべての実装は行ベースです。 1つ以上の式の組み合わせによって作成されたパターンは、データストリームの各行と比較されます。一致すると、使用しているツールの規定に従って、その行でアクションが実行されます。

たとえば、 grepでパターン一致が発生した場合 、通常のアクションは、その行をSTDOUTに渡し、パターンに一致しない行を破棄することです。 正規表現入門:例で見たように 、 -v オプションはそれらのアクションを逆にし、一致する行が破棄されるようにします。

データストリームの各行は、それ自体で評価されます。各データストリームラインをレコードと考えてください。正規表現を使用するツールは、一度に1つのレコードを処理します。一致が行われると、使用中のツールによって定義されたアクションが、一致する文字列を含む行で実行されます。

正規表現のビルディングブロック

次の表には、GNU grepによって実装される基本的なビルディングブロック式とメタ文字のリストが含まれています。 コマンド(および他のほとんどの正規表現の実装)とその説明。パターンで使用される場合、これらの式またはメタ文字はそれぞれ、解析されるデータストリーム内の単一の文字と一致します。

表現 説明

英数字

リテラル

A-Z、a-z、0-9

すべての英数字と一部の句読文字はリテラルと見なされます。したがって、文字 a 正規表現では、解析されるデータストリームの文字「a」と常に一致します。これらの文字にあいまいさはありません。各リテラル文字は1つだけの文字と一致します。
。 (ドット) ドット(。)メタ文字は、最も基本的な表現形式です。これは、パターンで検出された位置にある任意の1文字と一致します。したがって、パターン b.g 「big」、「bigger」、「bag」、「baguette」、「bog」には一致しますが、「dog」、「blog」、「hug」、「lag」、「gag」、「leg」などには一致しません。 。

ブラケット式

[キャラクターリスト]

GNU grepはこれをブラケット式と呼び、Bashシェルのセットと同じです。角かっこは、パターン内の1つの文字の位置に一致する文字のリストを囲みます。 [abcdABCD] 大文字または小文字の「a」、「b」、「c」、または「d」の文字と一致します。 [a-dA-D] 同じ一致を作成する文字の範囲を指定します。 [a-zA-Z] 大文字と小文字のアルファベットに一致します。

[:クラス名:]

キャラクタークラス

これは、正規表現の標準化におけるPOSIXの試みです。クラス名は明白であるはずです。たとえば、 [:alnum:] クラスはすべての英数字に一致します。他のクラスは[:digit:] これは、0〜9の任意の1桁に一致します。 [:alpha:] [:space:] 、 等々。ロケールによってソート順序が異なるため、問題が発生する可能性があることに注意してください。 grepを読む 詳細については、manページを参照してください。

^および$

アンカー

これらの2つのメタ文字は、それぞれ行の先頭と末尾に一致します。それらは、パターンの残りの部分を行の最初または最後に固定すると言われています。式^b.g 上記のように、解析される行の先頭で発生する場合にのみ、「big」、「bigger」、「bag」などに一致します。パターンb.g$ 「大きい」または「バッグ」と一致するのは、それらが行の最後にある場合のみですが、「大きい」とは一致しません。

いくつかの修飾子を続行する前に、これらのビルディングブロックを調べてみましょう。実験3で使用するテキストファイルは、私が以前教えていた古いLinuxクラス用に作成したラボプロジェクトからのものです。元々はLibreOfficeWriterodtファイルにありましたが、ASCIIテキストファイルに保存しました。表などの書式設定のほとんどが削除されましたが、結果として、この一連の実験に使用できる長いASCIIテキストファイルが作成されます。

例:目次エントリ

例を見て、今学んだことを調べてみましょう。まず、〜/ testsを作成します PWDのディレクトリを作成し(このシリーズの前の記事にまだ含まれていない場合は作成します)、GitHubからサンプルファイルをダウンロードします。

[student@studentvm1 testing]$  wget https://raw.githubusercontent.com/opensourceway/reg-ex-examples/master/Experiment_6-3.txt

まず、 lessを使用します Experiment_6-3.txtを調べて探索するコマンド その内容のアイデアを得るために数分間ファイルします。

それでは、簡単な grepを使用してみましょう。 入力データストリームから行を抽出する式。目次(TOC)には、プロジェクトのリストと、PDFドキュメント内のそれぞれのページ番号が含まれています。 2桁で終わる行で始まる目次を抽出しましょう:

[student@studentvm1 testing]$  grep [0-9][0-9]$ Experiment_6-3.txt

このコマンドは、実際には私たちが望んでいるものではありません。 2桁で終わり、1桁のTOCエントリが欠落しているすべての行が表示されます。後の実験で、1桁以上の式を処理する方法を見ていきます。 lessでファイル全体を見る 、このようなことができます。

[student@studentvm1 testing]$ grep "^Lab Project" Experiment_6-3.txt | grep "[0-9]$"

このコマンドは、私たちが望むものにはるかに近いものですが、完全にはありません。ドキュメントの後半から、これらの式にも一致する行がいくつかあります。余分な行を調べて完全なドキュメントでそれらを見ると、目次の一部ではないのに、なぜそれらが一致するのかがわかります。

このコマンドは、「ラボプロジェクト」で始まらない目次エントリも見逃します。時々、この結果はあなたができる最善のものであり、それは私たちが以前に持っていたよりも目次をよりよく見ることができます。これら2つのgrepを組み合わせる方法を見ていきます。 後の実験でインスタンスを1つにまとめます。

それでは、このコマンドを少し変更して、POSIX式を使用してみましょう。二重中括弧( [[]] )に注意してください )その周り:

[student@studentvm1 testing]$ grep "^Lab Project" Experiment_6-3.txt | grep "[[:digit:]]$"

中括弧が1つあると、エラーメッセージが生成されます。

このコマンドは、前の試行と同じ結果をもたらします。

例:systemd

同じファイルで別のものを探しましょう:

[student@studentvm1 testing]$ grep systemd Experiment_6-3.txt

このコマンドは、ファイル内の「systemd」のすべての出現をリストします。 -iを使用してみてください 大文字で始まるインスタンスを含むすべてのインスタンスを確実に取得するためのオプション(「systemd」の正式な形式はすべて小文字です)。または、リテラル式を Systemdに変更することもできます 。

文字列systemdを含む行数を数えます 。私はいつも-iを使います 大文字と小文字を区別せずに検索式のすべてのインスタンスが確実に見つかるようにするには:

[student@studentvm1 testing]$ grep -i systemd Experiment_6-3.txt | wc
20      478     3098

ご覧のとおり、私は20行あり、同じ数である必要があります。

例:メタ文字

メタ文字を照合する例を次に示します。左角かっこ( [ )。まず、特別なことは何もせずに試してみましょう:

[student@studentvm1 testing]$  **grep -i "[" Experiment_6-3.txt**
grep: Invalid regular expression

このエラーは、[が原因で発生します メタ文字として解釈されます。 脱出する必要があります この文字に円記号を付けます( \ )メタ文字ではなくリテラル文字として解釈されるようにします:

[student@studentvm1 testing]$ grep -i "\[" Experiment_6-3.txt

ほとんどのメタ文字は、角かっこ式内で使用すると特別な意味を失います:

  • リテラルの]を含めるには 、リストの最初に配置します。
  • リテラルの^を含めるには 、最初以外の場所に配置します。
  • リテラルの[を含めるには 、最後に配置します。
繰り返し

正規表現は、文字または式の0回、1回、またはそれ以上の繰り返しを指定できる演算子を使用して変更できます。これらの繰り返し演算子は、パターンで使用されているリテラル文字またはメタ文字の直後に配置されます。

オペレーター 説明

正規表現では、 前の文字の多くで0または1回の出現を意味します。たとえば、 drives? 「ドライブ」および「ドライブ」と一致しますが、「ドライバー」とは一致しません。この結果は、の動作とは少し異なります。 グロブで。

* *の前の文字 無制限に0回以上一致します。この例では、 drives * 「drive」、「drives」、「drivesss」には一致しますが、「driver」には一致しません。繰り返しますが、これは *の動作とは少し異なります。 グロブで。
+ +の前の文字 1回以上一致します。一致が発生するためには、文字が少なくとも1回は行に存在している必要があります。一例として、 drives + 「drives」および「drivesss」と一致しますが、「drive」または「driver」とは一致しません。
{n} この演算子は、前の文字と正確にn回一致します。式drives{2} 「drives」と一致しますが、「drive」、「drives」、「drivesss」、または任意の数の末尾の「s」文字とは一致しません。ただし、「drivesssss」には文字列 drivesが含まれているため 、その文字列で一致が発生するため、その行は grepによる一致になります。 。
{n、} この演算子は、前の文字とn回以上一致します。式drives{2、} 「ドライブ」と一致しますが、「ドライブ」、「ドライブ」、「ドライブ」、「ドライブ」、または任意の数の末尾の「s」文字とは一致しません。 「drivesssss」には文字列drivesが含まれているため 、一致が発生します。
{、m} この演算子は、前の文字と一致するのはm回以内です。式drives{、2} 「drive」、「drives」、「drives」に一致しますが、「drivesss」や末尾の「s」文字は一致しません。繰り返しになりますが、「drivesssss」には文字列 drivesが含まれているためです。 、一致が発生します。
{n、m} この演算子は、前の文字と少なくともn回一致しますが、m回以下です。式drives{1,3} 「drives」、「drivess」、「drivesss」に一致しますが、「drivessss」や末尾の「s」文字は一致しません。繰り返しになりますが、「drivesssss」には一致する文字列が含まれているため、一致が発生します。

例として、次の各コマンドを実行し、結果を注意深く調べて、何が起こっているのかを理解します。

[student@studentvm1 testing]$  **grep -E files? Experiment_6-3.txt**
[student@studentvm1 testing]$  **grep -Ei "drives*" Experiment_6-3.txt**
[student@studentvm1 testing]$  **grep -Ei "drives+" Experiment_6-3.txt**
[student@studentvm1 testing]$  **grep -Ei "drives{2}" Experiment_6-3.txt**
[student@studentvm1 testing]$  **grep -Ei "drives{2,}" Experiment_6-3.txt**
[student@studentvm1 testing]$  **grep -Ei "drives{,2}" Experiment_6-3.txt**
[student@studentvm1 testing]$  **grep -Ei "drives{2,3}" Experiment_6-3.txt**

サンプルファイル内の他のテキストでこれらの修飾子を試してみてください。

メタ文字修飾子

調査する必要のある、興味深く重要な修飾子がまだいくつかあります。

修飾子 説明
< この特殊な式は、単語の先頭にある空の文字列と一致します。式 「fun」と「Function」には一致しますが、「refund」には一致しません。
> この特殊な式は、通常のスペース、つまり単語の末尾の空( "")文字列、および単語の末尾の1文字の文字列に通常表示される句読点と一致します。つまり、 environment> 「environment」、「environment」、「environment」に一致しますが、「environments」や「environmental」には一致しません。
^ 文字クラス式では、この演算子は文字のリストを無効にします。したがって、クラス [a-c] パターンのその位置で「a」、「b」、または「c」に一致するクラス [^ a-c] 「a」、「b」、「c」以外に一致します。
| 正規表現で使用する場合、 | メタ文字は論理「または」演算子です。正式には中置と呼ばれます または代替 オペレーター。これは、正規表現の開始:例ですでに発生しています。 、正規表現 "Team | ^ \ s * $"が表示された場所 「'Team'または( | )スペース、タブ、その他の印刷できない文字など、0個、1個、またはそれ以上の空白文字を含む空の行。 "
(および) 括弧(および) プログラミング言語での論理比較に使用されるような、パターン比較の特定のシーケンスを保証できるようにします。

これで、 \<を使用して単語の境界を指定する方法ができました。 および\> メタ文字。これは、パターンをさらに明確にできることを意味します。より複雑なパターンでロジックを使用することもできます。

例として、いくつかの単純なパターンから始めます。この最初のものは、ドライブのすべてのインスタンスを選択します ただし、ドライブではありません 、 drives 、または追加の末尾の「s」文字:

 [student@studentvm1 testing]$  **grep -Ei "\<drives\>" Experiment_6-3.txt**

次に、検索パターンを作成して、 tarへの参照を見つけましょう。 (tape archiveコマンド)および関連するリファレンス。最初の2回の反復では、 tar以上のものが表示されます 関連行:

[student@studentvm1 testing]$ grep -Ei "tar" Experiment_6-3.txt
[student@studentvm1 testing]$ grep -Ei "\<tar" Experiment_6-3.txt
[student@studentvm1 testing]$  grep -Ein "\<tar\>" Experiment_6-3.txt

-n 上記の最後のコマンドのオプションは、一致が発生した各行の行番号を表示します。このオプションは、検索パターンの特定のインスタンスを見つけるのに役立ちます。

ヒント: 一致するデータ行は、特に大きなファイルを検索する場合、単一の画面を超えて拡張される可能性があります。結果のデータストリームをlessユーティリティにパイプしてから、正規表現を実装するless検索機能を使用して、検索パターンとの一致の発生を強調表示することもできます。 lessの検索引数は次のとおりです: \

この次のパターンは、テストドキュメントで「シェルスクリプト」、「シェルプログラム」、「シェル変数」、「シェル環境」、または「シェルプロンプト」を検索します。括弧は、パターン比較が解決される論理的な順序を変更します。

[student@studentvm1 testing]$ grep -Eni "\<shell (script|program|variable|environment|prompt)" Experiment_6-3.txt

注: この記事は、2019年後半にApressからリリースされる、私のLinuxの本「Linuxの使用と管理:ZeroからSysAdmin」の第2巻の第6章を少し変更したものです。

前のコマンドから括弧を削除し、もう一度実行して違いを確認してください。

まとめ

これで、 grepの正規表現の基本的な構成要素について説明しました。 、それらを組み合わせて複雑でありながらエレガントな検索パターンを作成する方法は無限にあります。ただし、 grep は検索ツールであり、一致が行われたときにデータストリーム内のテキスト行を編集または変更する直接的な機能は提供しません。そのためには、 sedのようなツールが必要です。 、これについては次の記事で取り上げます。


Linux
  1. Command Grepを使用して検索しますか?

  2. ビッグデータの挑戦と約束

  3. Vhostsとサーバーブロックの基本

  1. CCPAとGDPRの概要

  2. システムディスクとデータディスクに関するFAQ

  3. ハニーポット チュートリアル – ハニーポットのモードと動作

  1. awkを使用したデータの抽出と表示

  2. データが重要である理由とその保護方法

  3. 複数行検索用の正規表現 (grep) が必要