{{category Python}} !!!gred.py {{ref gred.py.txt}} !!概要 grepとsedのあいのこのようなスクリプト。 オプション指定はgrep風。 正規表現指定構文はsed風だが、マッチ動作はgrep風。 思い出:Windowsのコマンドプロンプトでgrepが使いたくて作ったツール。ログ解析ソフトのサポートをしてたときにはかなり活躍した。 今はPowerShellでそれなりに高度な正規表現マッチができるので、いい時代になった。 !!動作要件 Python 3以上。 * ファイルのエンコードは、デフォルトではシステムのコンソールのエンコード(sys.stdout.encoding)と同じとみなされる。UNIX系のシステムであれば、環境変数LANGに依存する。WindowsではShift-JISとみなされる。エンコードが違うと、ほとんどの場合でファイルオープンの際にエラーになる(Pythonは自分がデコードできない文字に遭遇すると例外を発生させる)。 * ファイルパスの末尾にコロン(:)で区切って、ファイルのエンコードを明示的に指定することが可能。出力は sys.stdout.encoding になる。 > gred.py /regex/ target_file.txt:utf-8 * gredは引数として与えられた正規表現パターンをsys.stdin.encodingでデコードするので、上記文字コードの制約をクリアしていれば、日本語のマッチも問題なく行える。 !!オプション i: 正規表現で大文字小文字を区別しない。 n: 結果に元のファイルの行番号を表示する。cオプションとは排他。 c: マッチした行をカウントして、その合計結果だけを表示。s///とは一緒に使えない。また、nオプションとは排他。 v: 指定した正規表現にマッチしない行を表示する。s///とは一緒に使えない。 H: 表示結果の先頭にファイル名を表示。 !!grepのように使う 上記すべてのオプションが使用可能(cとnは排他)。 マッチさせたいパターンは、必ず//で囲う必要がある(/正規表現/)。grepのように単純に"pattern"として文字列を指定できない(この辺がsed風)ので注意。 !2008年6月26日の10時台のログのみ表示: python gred.py "/time=\"?2008-06-26 10:/" example.log * WindowsでCPythonをインストールした場合、拡張子".py"との関連付けが行われるので、スクリプトの実行時にPythonを明示的に呼び出す必要はない。以下、実行例は明示的にPythonを呼び出さない方法で記載する。 gred.py "/time=\"?2008-06-26 10:/" example.log * Windowsのコマンドプロンプトの場合、正規表現は""で囲わないと、メタ文字の一部が正しくスクリプトに渡らないので、注意(UNIXシェルの''と同じ)。 * また、ダブルクォーテーション(")文字を正規表現に含めたい場合は、この例のように\でエスケープする必要がある。 !ログ中にattackという文字列がある行の行数をカウント(cオプション): gred.py ic "/attack/" *.log * iオプションは、正規表現マッチで大文字小文字を区別しない。 * ファイル指定にワイルドカードを使用することができる(正確にはDOSのワイルドカードではなく、Pythonの標準モジュールglobを使って、UNIXシェルのグロブ展開を行う)。 * 各ファイルに/attack/にマッチする行が何行あるか、数字だけが表示される。ファイル名も表示したい場合には、以下のようにHオプションも指定する。 gred.py icH "/attack/" *.log !attackという文字列が含まれていない行だけをカウント(vオプション): gred.py icvH "/attack/" *.log !連続したパターンを指定する(後方参照の使用): gred.py "/(\d{1,2})\-\1/" example.log * 2桁までの同じ数字がハイフンで区切られているパターン(9-9、33-33など)にマッチする。 正規表現内での後方参照は、\numberが使える(Pythonの正規表現の仕様どおり)。 !フィルタ結果に元のファイルの行番号を表示(nオプション): gred.py n "/port scan/" example.log !!sed風の置換コマンド(s///)を使う s/正規表現/置換文字列/ iオプション、nオプション、Hオプションが使用可能。 置換処理された文字列が標準出力に出力される。 置換は各行に対してグローバルに行われる。 置換が行われなかった行も、すべて表示される(置換が行われた行のみ表示、という動作はない)。 置換文字列は、Pythonの文字列エスケープルールにしたがって解釈される(Pythonは、定義されていないエスケープを発見した場合、エスケープ文字(\)を削除せずに残す)。ただし、例外的にスラッシュのエスケープ(\/)だけはこのスクリプトによって処理され、リテラルのスラッシュ文字(/)に置き換わる。 !ログ中の「tcp/80」という表現を、「http」に置換: gred.py "s/tcp\/80/http/" example.log > replaced_example.log * スラッシュ記号(/)はバックスラッシュ(\)でエスケープする。 !ログ中の「tcp/80」という表現を、「80/tcp」に置換: gred.py "s/(tcp)\/(80)/\2\/\1/" example.log > replaced_example.log * 置換文字列内でも、\numberで後方参照が使える。re モジュールの re.sub() に渡して処理させているだけなので、置換文字列内だけで有効な \g も使える。