103.7 レッスン 2
Certificate: |
LPIC-1 |
---|---|
Version: |
5.0 |
Topic: |
103 GNUおよびUnixコマンド |
Objective: |
103.7 正規表現を使用してテキストファイルを検索する |
Lesson: |
2 of 2 |
はじめに
コマンドをパイプでつなげることにより、正規表現を使ってフィルターを組み合わせてデータストリームの処理ができます。システム管理だけでなくデータマイニングの領域でも正規表現は重要な技術になります。正規表現を使ってファイルやテキストを処理するのに最適な2つのコマンドがあります。grep
と sed
です。grep
はパターン発見器で、sed
はストリームエディタです。これらは単独でも有用ですが、他のプログラムと協働する場面で際立ちます。
パターン発見器:grep
grep
が長いテキストファイルを探索する手助けになることがよくあります。正規表現をテキストファイルの各行に適用するフィルターとして使うのです。例えば、ある単語で始まる行だけを表示するのに使えます。カーネルモジュールの設定ファイルでオプション行だけを表示するならこのようにします。
$ grep '^options' /etc/modprobe.d/alsa-base.conf options snd-pcsp index=-2 options snd-usb-audio index=-2 options bt87x index=-2 options cx88_alsa index=-2 options snd-atiixp-modem index=-2 options snd-intel8x0m index=-2 options snd-via82xx-modem index=-2
パイプ(|
)を使えばコマンドの出力を直接 grep
の入力にリダイレクトできます。以下の例では、文字クラスを使って、fdisk -l
の出力のうち、Disk/dev/sda
または Disk/dev/sdb
で始まる行だけを表示しています。
# fdisk -l | grep '^Disk /dev/sd[ab]' Disk /dev/sda: 320.1 GB, 320072933376 bytes, 625142448 sectors Disk /dev/sdb: 7998 MB, 7998537728 bytes, 15622144 sectors
マッチした行を表示するだけでは事足りないこともあるでしょう。そういうときは、grep
のオプションを指定して動作の調整ができます。例えば、-c
または --count
オプションを指定すると、マッチした行の総数がわかります。
# fdisk -l | grep '^Disk /dev/sd[ab]' -c 2
オプション指定は正規表現の前でも後でも構いません。grep
でよく使うオプションは次のとおりです。
-c
または--count
-
マッチした行を表示するのではなく、マッチした行の総数を表示します。
-i
または--ignore-case
-
大文字と小文字を区別せずにマッチをします。
-f FILE
または--file=FILE
-
正規表現が書かれたファイルを指定します。
-n
または--line-number
-
行番号を表示します。
-v
または--invert-match
-
マッチしなかった行を表示します。
-H
または--with-filename
-
行がマッチしたファイル名も表示します。
-z
または--null-data
-
入出力データストリームをNull文字で区切った部分ごとに処理します。このオプションを指定しないデフォルトでは、 改行 で区切った行ごとに処理します。(ファイル名に改行文字が含まれるかもしれないという理由などにより)
find
コマンドで-print0
オプションを指定した出力をgrep
で処理する場合には、-z
または--null-data
オプションを指定するとうまくいきます。
複数のファイルが与えられるとデフォルトで -H
オプションが指定されるのですが、一つずつファイルが与えられる場合にはデフォルトで -H
オプションが指定されません。例えば、次のように、grep
が find
によって直接呼び出される場合に問題となります。
$ find /usr/share/doc -type f -exec grep -i '3d modeling' "{}" \; | cut -c -100 artistic aspects of 3D modeling. Thus this might be the application you are This major approach of 3D modeling has not been supported oce is a C++ 3D modeling library. It can be used to develop CAD/CAM softwares, for instance [FreeCad
この例では、find
が /usr/share/doc
以下のすべてのファイルを一つずつ grep
に渡し、そのファイル内に 3d modeling
が含まれているかどうかを大文字と小文字を区別せずに検索します。100文字分だけ切り出すために cut
へパイプでつなげています。しかし、マッチした行がどのファイルの行なのかがわかりません。grep
に -H
オプションを指定するとわかるようになります。
$ find /usr/share/doc -type f -exec grep -i -H '3d modeling' "{}" \; | cut -c -100 /usr/share/doc/openscad/README.md:artistic aspects of 3D modeling. Thus this might be the applicatio /usr/share/doc/opencsg/doc/publications.html:This major approach of 3D modeling has not been support
これでマッチした行がどのファイルの行なのかがわかります。さらに情報を得るために、マッチした前後の行を表示させることもできます。
$ find /usr/share/doc -type f -exec grep -i -H -1 '3d modeling' "{}" \; | cut -c -100 /usr/share/doc/openscad/README.md-application Blender), OpenSCAD focuses on the CAD aspects rather t /usr/share/doc/openscad/README.md:artistic aspects of 3D modeling. Thus this might be the applicatio /usr/share/doc/openscad/README.md-looking for when you are planning to create 3D models of machine p /usr/share/doc/opencsg/doc/publications.html-3D graphics library for Constructive Solid Geometry (CS /usr/share/doc/opencsg/doc/publications.html:This major approach of 3D modeling has not been support /usr/share/doc/opencsg/doc/publications.html-by real-time computer graphics until recently.
-C1
や --context=1
というオプションを指定すると、マッチした前後の行を1行ずつ含めて結果を表示します。コンテキスト(文脈)を表示するということです。出力ではファイル名の直後に -
(マイナス)がつけられます(マッチした行はファイル名の直後に :
(コロン)がつけられます)。上の例のように -1
という指定でも同じ結果になります。前の行と後の行の表示行数を別々に指定することもできます。
grepには2つの補完的なプログラムがあります。egrep
と fgrep
です。egrep
は grep -E
と同じで、バターンを指定する正規表現が基本正規表現から拡張正規表現に切り替わります。例えば、egrep
では、マッチさせたい文字列を |
(パイプ)で区切る選択が使えます。
$ find /usr/share/doc -type f -exec egrep -i -H -1 '3d (modeling|printing)' "{}" \; | cut -c -100 /usr/share/doc/openscad/README.md-application Blender), OpenSCAD focuses on the CAD aspects rather t /usr/share/doc/openscad/README.md:artistic aspects of 3D modeling. Thus this might be the applicatio /usr/share/doc/openscad/README.md-looking for when you are planning to create 3D models of machine p /usr/share/doc/openscad/RELEASE_NOTES.md-* Support for using 3D-Mouse / Joystick / Gamepad input dev /usr/share/doc/openscad/RELEASE_NOTES.md:* 3D Printing support: Purchase from a print service partne /usr/share/doc/openscad/RELEASE_NOTES.md-* New export file formats: SVG, 3MF, AMF /usr/share/doc/opencsg/doc/publications.html-3D graphics library for Constructive Solid Geometry (CS /usr/share/doc/opencsg/doc/publications.html:This major approach of 3D modeling has not been support /usr/share/doc/opencsg/doc/publications.html-by real-time computer graphics until recently.
この例では、3D modeling
または 3D printing
のどちらでもマッチします。-i
オプションを指定しているので大文字と小文字を区別しません。-o
オプションを指定するとテキストストリームのマッチした部分だけを表示できます。
fgrep
は grep -F
と同じで、正規表現の解析をしません。そのままの表現を単純にマッチしたいときに便利です。$
(ドル記号)や .
(ドット)などの特殊文字も正規表現での特殊な意味ではなくそのままの記号として解釈されます。
ストリームエディタ:sed
sed
はテキストベースのデータを非対話的に修正するためのプログラムです。(通常のエディタのように)画面に表示されるテキストを直接思いのままにタイピングするのではなく、事前に定義した指示によって編集を行います。今時風に、テンプレートパーサーだと言ってもよいでしょう。あるテキストを入力として受け取り、事前に決められた場所や正規表現でマッチした部分をカスタムコンテンツに入れ替えるのです。
sedはStream EDitorの略であり、その名前が示すように、パイプを通過するストリーミングテキストの編集にうってつけです。編集指示をスクリプトファイルに保存している場合には sed -f スクリプトファイル名
、コマンドラインから直接スクリプトを実行する場合には sed -e スクリプト
とするのが基本です。-f
も -e
もなければ、最初の非オプションパラメータがスクリプトファイル名として用いられます。sed
の引数にファイルパスを渡せばそのファイルの内容が sed
の入力になります。
sed
のスクリプト内のコマンドは1文字で表されます。オプションやアドレスの後にスクリプトを書き、それが各行に適用されます。アドレスは行番号、行範囲、正規表現のいずれかです。例えば、1d
でテキストストリームの最初の行を削除できます。1
が行番号を指定するアドレスで、d
が削除を意味するスクリプトです。1から12までの素因数を返す factor `seq 12`
の出力を利用して sed
の使い方を見ていきましょう。
$ factor `seq 12` 1: 2: 2 3: 3 4: 2 2 5: 5 6: 2 3 7: 7 8: 2 2 2 9: 3 3 10: 2 5 11: 11 12: 2 2 3
1d
で最初の行を削除します。
$ factor `seq 12` | sed 1d 2: 2 3: 3 4: 2 2 5: 5 6: 2 3 7: 7 8: 2 2 2 9: 3 3 10: 2 5 11: 11 12: 2 2 3
,
(カンマ)で行範囲をアドレスに指定できます。
$ factor `seq 12` | sed 1,7d 8: 2 2 2 9: 3 3 10: 2 5 11: 11 12: 2 2 3
;
(セミコロン)で区切って続けて書けば複数のスクリプトを実行できます。;
(セミコロン)がシェルに解釈されないように "
(ダブルクオート)で囲ってください。
$ factor `seq 12` | sed "1,7d;11d" 8: 2 2 2 9: 3 3 10: 2 5 12: 2 2 3
上の例では2つの削除スクリプトが実行されます。1行目から7行目までの削除と、11行目の削除です。アドレスは正規表現でも構いません。正規表現にマッチした行にだけスクリプトが適用されます。
$ factor `seq 12` | sed "1d;/:.*2.*/d" 3: 3 5: 5 7: 7 9: 3 3 11: 11
:.*2.*
という正規表現は、:
(コロン)より後のどこかに2があるとマッチするので、上の例は2を素因数に持つ数字の行を削除することになります。sed
では、/
(スラッシュ)の間に置かれたものが正規表現だとみなされます。デフォルトでは基本正規表現です。例えば、sed -e "/^#/d" /etc/services
を実行すると、#
で始まる行(コメント行)以外の /etc/services
の内容が表示されます。
削除スクリプトの d
以外にも sed
にはいろいろなスクリプトがあります。行置換スクリプトは次のとおりです。
$ factor `seq 12` | sed "1d;/:.*2.*/c REMOVED" REMOVED 3: 3 REMOVED 5: 5 REMOVED 7: 7 REMOVED 9: 3 3 REMOVED 11: 11 REMOVED
スクリプト c REMOVED
は、対象行を REMOVED
というテキストに置換します。上の例では、正規表現 :.*2.*
にマッチする各行に対して行置換スクリプト c REMOVED
が実行されます。スクリプト a TEXT
はマッチした行の次の行に TEXT
というテキストを追加します。スクリプト r FILE
も同様にテキストを追加するのですが、FILE
で指定されたファイルの内容をコピーします。スクリプト w
は r
の反対のことをします。指定されたファイルに対してマッチした行を書き込みます。
sed
で断トツによく使われるスクリプトは s/FIND/REPLACE/
です。正規表現 FIND
にマッチした部分をテキスト REPLACE
に置換します。例えば、スクリプト s/hda/sda/
は、正規表現にマッチした hda
を sda
に置換します。その行で最初にマッチした部分だけが置換されます。s/hda/sda/g
のように g
フラグを付け加えるとマッチした部分が全部置換されます。
もっと実践的な sed
の使い方を見てみましょう。あるクリニックが患者に翌日の予約をリマインドするショートメッセージを送るという場面を想定しています。メッセージの送信は商用メッセージサービスが提供するAPIを通じて行うことになるでしょうし、こうしたメッセージの送信は患者の予約を管理しているアプリケーションから指定した時間やその他の何らかのイベントによってトリガーするのが一般的でしょうが、ここでは翌日の予約データからメッセージを組み立てる処理だけを扱います。以下のような翌日の予約データを表形式で格納した appointments.csv
というファイルがあると仮定して(CSVファイルはデータベースからデータをエクスポートする際の標準的なファイル形式です)、template.txt
というテンプレートファイルを基に sed
で各患者に送るテキストメッセージを組み立てます。
$ cat appointments.csv "NAME","TIME","PHONE" "Carol","11am","55557777" "Dave","2pm","33334444"
最初の行は各列のラベルになっています。そのラベルをテンプレートファイルに埋め込みます。
$ cat template.txt Hey <NAME>, don't forget your appointment tomorrow at <TIME>.
タグとして使うために小なり記号 <
と大なり記号 >
をラベルの前後に入れています。以下のシェルスクリプトは、翌日の予約データを解析し、template.txt
テンプレートファイルを基にメッセージを組み立て、商用メッセージサービスが提供するAPIへと送る準備をします。
#! /bin/bash TEMPLATE=`cat template.txt` TAGS=(`sed -ne '1s/^"//;1s/","/\n/g;1s/"$//p' appointments.csv`) mapfile -t -s 1 ROWS < appointments.csv for (( r = 0; r < ${#ROWS[*]}; r++ )) do MSG=$TEMPLATE VALS=(`sed -e 's/^"//;s/","/\n/g;s/"$//' <<<${ROWS[$r]}`) for (( c = 0; c < ${#TAGS[*]}; c++ )) do MSG=`sed -e "s/<${TAGS[$c]}>/${VALS[$c]}/g" <<<"$MSG"` done echo curl --data message=\"$MSG\" --data phone=\"${VALS[2]}\" https://mysmsprovider/api done
実用レベルのスクリプトにするには、認証、エラーチェック、ログの記録などが求められますが、出発点となる基本的な機能は出揃っています。sed
の最初のスクリプトは、1s/^"//;1s/","/\n/g;1s/"$//p
に 1
というアドレスがあるので、1行目にだけ作用します。1s/^"//
と 1s/"$//
で行頭と行末の "
(ダブルクオート)を取り除き、1s/","/\n/g
でフィールドの区切りを ","
(ダブルクオート、カンマ、ダブルクオート)から \n
(改行)に置換しています。ここではカラム名が書かれた1行目だけがほしいので、マッチしなかった行が出力されないように -n
オプションを指定しています。ただし、マッチした行を出力するために、p
フラグが最後に必要となります。このようにして取得されたタグは、Bashの配列として変数 TAGS
に格納されます。予約行が mapfile
コマンドでBashの配列として変数 ROWS
に格納されます。
for
ループで ROWS
変数の各予約行の処理をしています。ヒア文字列として使われている変数 ${ROWS[$r]}
に格納されている予約の各行の行頭と行末の "
(ダブルクオート)を取り除き、 ","
(ダブルクオート、カンマ、ダブルクオート)を \n
(改行)に置換しています。タグを取得するのに使ったコマンドとほとんど同じです。このようにして分離された値が配列変数 VALS
に格納されます。配列の添え字の0、1、2がそれぞれ NAME
、TIME
、PHONE
に対応します。
最後に、入れ子になっている for
ループで TAGS
配列を順番に処理して、テンプレート内のタグを VALS
の対応する値に置換します。変数 MSG
は生成されたテンプレートのコピーを保持します。s/<${TAGS[$c]}>/${VALS[$c]}/g
コマンドで順次置換されて更新されていきます。
こうして "Hey Carol, don’t forget your appointment tomorrow at 11am."
のようなメッセージが生成されることになります。そのメッセージを curl
コマンドでHTTPリクエストを通じてパラメータとして送り、ショートメールを送信できるというわけです(これは架空の例ですから、curl
コマンドを実行するのではなく echo
で表示するようにしています)。
grepとsedを組み合わせて使う
もっと複雑なテキストマイニングでは grep
コマンドと sed
コマンドを同時に使うこともあります。システム管理者としてサーバーへのログイン試行を精査したいとしましょう。/var/log/wtmp
ファイルがすべてのログイン及びログアウトを記録しており、/var/log/btmp
ファイルが失敗したログイン試行を記録しています。これらのファイルはバイナリ形式で書かれているため、それぞれ last
コマンドと lastb
コマンドで読み出します。
lastb
は失敗したログイン試行のユーザー名とIPアドレスを出力します。
# lastb -d -a -n 10 --time-format notime user ssh:notty (00:00) 81.161.63.251 nrostagn ssh:notty (00:00) vmd60532.contaboserver.net pi ssh:notty (00:00) 132.red-88-20-39.staticip.rima-tde.net pi ssh:notty (00:00) 132.red-88-20-39.staticip.rima-tde.net pi ssh:notty (00:00) 46.6.11.56 pi ssh:notty (00:00) 46.6.11.56 nps ssh:notty (00:00) vmd60532.contaboserver.net narmadan ssh:notty (00:00) vmd60532.contaboserver.net nominati ssh:notty (00:00) vmd60532.contaboserver.net nominati ssh:notty (00:00) vmd60532.contaboserver.net
-d
オプションはIPアドレスの数字をホスト名に変換して表示します。ホスト名は失敗したログイン試行をしたプロバイダーやホスティングサービスについての手がかりになるかもしれません。-a
オプションはホスト名を最終列に表示するようにします。後でその最終列にフィルターを適用するので、そのための調整です。--time-format notime
オプションは、ログイン試行の発生した日時を出力しないようにします。多くの失敗したログイン試行があると lastb
コマンドは時間がかかることがあるので、-n 10
オプションで出力を10件に限定しています。
すべてのリモートIPアドレスがホスト名と関連づけられているわけではないため、DNSの逆引きができないことがあり、その部分はそのままIPアドレスが表示されます。行末のホスト名にマッチする正規表現を書いてもよいのですが、おそらく行の最後の1文字が数字かアルファベットかを判定する正規表現を書くほうが簡単です。以下の例では、失敗したログイン試行のリストを grep
コマンドが標準入力から受け取り、ホスト名を取得できなかった行を除去して表示します。
# lastb -d -a --time-format notime | grep -v '[0-9]$' | head -n 10 nvidia ssh:notty (00:00) vmd60532.contaboserver.net n_tonson ssh:notty (00:00) vmd60532.contaboserver.net nrostagn ssh:notty (00:00) vmd60532.contaboserver.net pi ssh:notty (00:00) 132.red-88-20-39.staticip.rima-tde.net pi ssh:notty (00:00) 132.red-88-20-39.staticip.rima-tde.net nps ssh:notty (00:00) vmd60532.contaboserver.net narmadan ssh:notty (00:00) vmd60532.contaboserver.net nominati ssh:notty (00:00) vmd60532.contaboserver.net nominati ssh:notty (00:00) vmd60532.contaboserver.net nominati ssh:notty (00:00) vmd60532.contaboserver.net
grep
コマンドに -v
オプションを指定すると正規表現にマッチしなかった行だけを表示します。[0-9]$
という正規表現は行末が数字である行にマッチするので、ホスト名を取得できなかった行を捕捉します。よって、grep -v '[0-9]$'
は、ホスト名を取得できた行だけを表示します。
この出力に対してさらにフィルターを適用しましょう。各行のドメイン名だけを残し、その他の部分を除去します。sed
コマンドの置換スクリプトの出番です。ドメイン名をグループ化して後方参照で行全体と置換します。
# lastb -d -a --time-format notime | grep -v '[0-9]$' | sed -e 's/.* \(.*\)$/\1/' | head -n 10 vmd60532.contaboserver.net vmd60532.contaboserver.net vmd60532.contaboserver.net 132.red-88-20-39.staticip.rima-tde.net 132.red-88-20-39.staticip.rima-tde.net vmd60532.contaboserver.net vmd60532.contaboserver.net vmd60532.contaboserver.net vmd60532.contaboserver.net vmd60532.contaboserver.net
.* \(.*\)$
の \(
と \)
(エスケープされた丸かっこ)が行のドメイン名の部分、すなわち最後のスペースから行末までの部分をグループ化して記憶します。この例では、その記憶された部分を \1
で後方参照し、行全体と置換しています。
同じリモートホストが何度もログインしようとしているので、同じドメイン名が繰り返されています。繰り返しを表示しないようにするためには、(sort
コマンドで)ソートしてから uniq
コマンドに渡します。
# lastb -d -a --time-format notime | grep -v '[0-9]$' | sed -e 's/.* \(.*\)$/\1/' | sort | uniq | head -n 10 116-25-254-113-on-nets.com 132.red-88-20-39.staticip.rima-tde.net 145-40-33-205.power-speed.at tor.laquadrature.net tor.momx.site ua-83-226-233-154.bbcust.telenor.se vmd38161.contaboserver.net vmd60532.contaboserver.net vmi488063.contaboserver.net vmi515749.contaboserver.net
これはいろいろなコマンドを組み合わせて望む出力を得るにはどうしたらよいかを示す格好の例です。このホスト名のリストは、ファイアウォールの拒否ルールの設定その他のセキュリティ対策を実施する際に活用できます。
演習
-
last
コマンドはログインしたユーザーの履歴をIPアドレスも含めて表示します。そのlast
の出力をegrep
コマンドでフィルタリングしてIPv4アドレスだけを表示するようにしてください。IPv4アドレス以外の情報は必要ありません。 -
-print0
オプションを指定して実行されたfind
コマンドの出力を正常にフィルタリングするにはgrep
コマンドにどのオプションを指定すればよいでしょうか。 -
uptime -s
コマンドは2019-08-05 20:13:22
のように直近のシステム起動日時を表示します。uptime -s | sed -e 's/(.*) (.*)/\1/'
コマンドの実行結果はどうなるでしょうか。 -
マッチした行を表示するのではなくマッチした行の総数を表示するには、
grep
にどのオプションを指定しますか。
発展演習
-
HTMLファイルの基本構造は、
html
、head
、body
です。例えば次のようなファイルです。<html> <head> <title>News Site</title> </head> <body> <h1>Headline</h1> <p>Information of interest.</p> </body> </html>
body
要素とその中身だけを表示するsed
コマンドのアドレスを書いてください。 -
sed
コマンドでHTML文書からタグをすべて取り除きテキストだけを表示してください。 -
.ovpn
というサフィックスのファイルは、設定情報とともにクライアントの鍵と証明書の中身を含められるので、VPNクライアントを設定する際によく用いられます。鍵と証明書は元々別ファイルにあるので、その中身を.ovpn
ファイルにコピーしなければなりません。以下のようなテンプレートを用意してその作業を楽にしましょう。client dev tun remote 192.168.1.155 1194 <ca> ca.crt </ca> <cert> client.crt </cert> <key> client.key </key> <tls-auth> ta.key </tls-auth>
ca.crt
、client.crt
、client.key
、ta.key
ファイルがカレントディレクトリにあるとします。sed
コマンドで上記のテンプレートファイル(client.template
)の該当箇所を各ファイルの内容に置換して、client.ovpn
ファイルを作成してください。
まとめ
このレッスンでは正規表現に関連する2つの重要なLinuxコマンドを説明しました。grep
と sed
です。これらのコマンドとさまざまなコマンドを組み合わせて、テキストの抽出や解析を行うシェルスクリプトを書くことができます。このレッスンは以下の順で取り上げました。
-
grep
とその派生コマンドであるegrep
やfgrep
の使い方 -
sed
のスクリプトでテキストを処理する方法 -
grep
とsed
を使った正規表現の応用例
演習の解答
-
last
コマンドはログインしたユーザーの履歴をIPアドレスも含めて表示します。そのlast
の出力をegrep
コマンドでフィルタリングしてIPv4アドレスだけを表示するようにしてください。IPv4アドレス以外の情報は必要ありません。last -i | egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'
-
-print0
オプションを指定して実行されたfind
コマンドの出力を正常にフィルタリングするにはgrep
コマンドにどのオプションを指定すればよいでしょうか。-z
オプションまたは--null-data
オプションです。例えばfind . -print0 | grep -z 正規表現
のようにします。 -
uptime -s
コマンドは2019-08-05 20:13:22
のように直近のシステム起動日時を表示します。uptime -s | sed -e 's/(.*) (.*)/\1/'
コマンドの実行結果はどうなるでしょうか。エラーが発生します。
sed
はデフォルトでは基本正規表現を使いますから、(
と)
(丸かっこ)をエスケープしなければなりません(訳注:-r
オプションで拡張正規表現を使用することもできます)。 -
マッチした行を表示するのではなくマッチした行の総数を表示するには、
grep
にどのオプションを指定しますか。-c
オプションを指定します。
発展演習の解答
-
HTMLファイルの基本構造は、
html
、head
、body
です。例えば次のようなファイルです。<html> <head> <title>News Site</title> </head> <body> <h1>Headline</h1> <p>Information of interest.</p> </body> </html>
body
要素とその中身だけを表示するsed
コマンドのアドレスを書いてください。body
要素とその中身だけを表示するアドレスは/<body>/,/<\/body>/
です。sed -n -e '/<body>/,/<\/body>/p'
のように実行します。-n
オプションで行の表示をしないようにして、マッチした行を表示するp
スクリプトを実行しています(訳注:1,7
で1行目から7行目までの行範囲を指定するのと同じように、/<body>/,/<\/body>/
で<body>
の行から</body>
の行までの範囲を正規表現で指定しています)。 -
sed
コマンドでHTML文書からタグをすべて取り除きテキストだけを表示してください。sed
でs/<[^>]*>//g
と書くと、<>
で囲われた部分を空の文字列に置換します。 -
.ovpn
というサフィックスのファイルは、設定情報とともにクライアントの鍵と証明書の中身を含められるので、VPNクライアントを設定する際によく用いられます。鍵と証明書は元々別ファイルにあるので、その中身を.ovpn
ファイルにコピーしなければなりません。以下のようなテンプレートを用意してその作業を楽にしましょう。client dev tun remote 192.168.1.155 1194 <ca> ca.crt </ca> <cert> client.crt </cert> <key> client.key </key> <tls-auth> ta.key </tls-auth>
ca.crt
、client.crt
、client.key
、ta.key
ファイルがカレントディレクトリにあるとします。sed
コマンドで上記のテンプレートファイル(client.template
)の該当箇所を各ファイルの内容に置換して、client.ovpn
ファイルを作成してください。sed -r -e 's/(^[^.]*)\.(crt|key)$/cat \1.\2/e' < client.template > client.ovpn
このコマンドは、
client.template
ファイルを入力として受け取り、行末が.crt
または.key
の行をその行と同じ名前のファイルの中身に置き換えて、client.ovpn
ファイルに出力します。-r
オプションを指定して拡張正規表現を使用します。正規表現の最後のe
はcat
コマンドの実行結果で置換するという意味です。後方参照の\1
と\2
は、マッチしたファイル名とサフィックスにそれぞれ対応します。