FreeBSDセットアップ「つまみぐい」その9
ちょっと手ごわいソフトウェアを使う
# どれも有名なソフトウェアばかりで、ぐぐればいくらでも解説が見つかるし、
# 解説書も豊富なので、詳しくはそちらを参照。ここでは紹介だけに留める。
awkやらperlやらrubyやら
http://aoki2.si.gunma-u.ac.jp/Hanasi/Algo/awk.html
http://www.att.or.jp/perl/man/
http://www.ruby-lang.org/ja/
http://ruby.mirror.easynet.be/ja/uguide/uguide00.html
http://www.python.jp/Zope/
どれも有名なインタープリタ言語で、非力だがsortやgrepなどの基本コマンドと
操作感が似ているawk、多少クセはあるが強力で汎用性も普及率も移植性も高いperl、
普及率はawkやperlに及ばないものの後発のためポテンシャルが高く今風なruby、
とそれぞれに特徴がある。
# この他にも、pythonやphpなど、いろいろなインタープリタ言語がある。
シェルから(主にテキスト処理をさせるために)使うことも可能で、たとえば、
> cat /dir1/CHECKSUM.md5 /dir2/CHECKSUM.md5 | awk '{print $4}' | uniq -d
とやってMD5sumの一致するファイルを探したり、
> perl -pe 's/うんたら/かんたら/g' < file1
とやって正規表現を使った置換をしたりと、いろいろと便利な使い方ができる。
http://x68000.q-e-d.net/~68user/unix/pickup?awk
http://x68000.q-e-d.net/~68user/unix/pickup?perl
http://www.legacyst.com/naotokun/unixer/
# rubyもperlと同様、-pオプション(出力付き自動ループ)と
# -eオプション(コマンドラインからスクリプトを指定)を指定して
# シェルから利用できる。
シェル(もしくはシェルスクリプト)から呼び出して使う分にはawk(パイプを
使ってsedやgrepやuniqなどと併用する)が手軽だが、perlの方がスマートだし
複雑な作業にも対応しやすい。perlについては、Shell.pmとかperlshというのを
使って、コマンドインタープリタ的に使うことも可能らしい。
http://www.kt.rim.or.jp/~kbk/perl5.005/perlfaq3.html#Is_there_a_Perl_shell_
# 筆者はShell.pmの中身もperlshの中身も読んだことがないし、ほとんど理解していない。
正規表現も強力で、変態^h^h達人の域まで達している人たちもいる。
http://www.din.or.jp/~ohzaki/regex.htm
# 後発のrubyも、(perlをお手本にしたらしく)強力な正規表現が可能なはずだが、
# 歴史が浅いためか、ここまで激しい話しは聞いたことがない。
正規表現自体については下記を参照。
http://www.kt.rim.or.jp/~kbk/regex/regex.html
http://www.sixnine.net/regexp/
http://www5a.biglobe.ne.jp/~n_rieko/perl/8.htm
http://www.ruby-lang.org/ja/20020314.html
edコマンドを基準にした限定正規表現(Basic Regular Expression)と
egrepコマンドを基準にした拡張正規表現(Extended Reuglar Exression)のほか、
perl互換の正規表現などいろいろなものあるが、基本的な部分はあまり変わらない。
そこそこの長さのスクリプトを書こうと思うとrubyが文句なしに強力だが、
手っ取り早さとパクリネタの多さではperlに一日の長がある。正規表現が強力で
テキスト処理に強かったことから、フリーで公開されている学術用のデータ処理
スクリプトには、perlで書かれたものが多い。一方awkはどうしても非力だし
複雑な処理をさせようと思うとかなり手間がかかる(世の中には職人的な技術を
持った人もいるが、awkを相当愛していないとその域までは到達できないだろう)。
perlについては
http://takenaka-akio.cool.ne.jp/doc/perl_kiso/
http://wisdom.sakura.ne.jp/programming/perl/
http://lll.physics.gifu-u.ac.jp/~tasaka/perl/
あたりが非常に参考になる。
perlスクリプトをWindowsマシンで動かすのは多少面倒だが、スクリプトから
実行形式のバイナリ(.exeファイル)を生成するツールもある。
# 最低1台は、perl(ActivePerl)が動くWindowsを用意する必要があるが。
PAR:スクリプトとインタープリタと利用するライブラリ(自動検出可能で
手動でも追加できる)を1ファイルにまとめる。作成したバイナリを公開する場合は、
インタープリタやライブラリのライセンスに注意する。
http://namazu.org/~satoru/diary/20040716.html
http://perldoc.jp/docs/modules/PAR-0.75/script/pp.pod
http://par.perl.org/
gldファイルを読み込む箇所を
my $fileWindow=PAR::read_file('hoge.gld');
としておく(事前にuse PARはしておく)ことと、
デザインオブジェクトの生成方法を「newLoad」から「newScalar」に変更する
my $objDesign = Win32::GUI::Loft::Design->newScalar($fileWindow)
ことがポイントらしい。
http://take4.dynsite.net/mt/archives/000019.html
perlcc:perlスクリプトをCのソースコードに変換してから普通にコンパイルする。
多分、生成されたCのソースを手動で修正するのが前提なのだと思う。perlを入れると
標準でバンドルされている(のだと思う、多分)。元のスクリプトが複雑だと
変換の精度も落ちるらしい(まあ当然)。
http://fleur.hio.jp/~hio/perldoc/mix/bin/perlcc.html
perl2exe:PARと似たような方式(だと思う)。シェアウェア。
http://www.indigostar.com/perl2exe.htm
rubyやphpにも似たようなツールがあるのだろうが、筆者は知らない。
viとかemacsとか
viは「どんな環境でも動く」ことを前提に最大限の拡張を施したエディタで、
nviやBSD系で育ったvimなどの派生がある。
# debianがnviを「新 vi。オリジナルの vi と同じバグを持つ。」と
# 紹介しているのにはちょっと笑った。
どんな環境でも動くというのは、シングルユーザーモードでの起動時に
利用可能であるということだけでなく、キーマッピンッグによっては
期待通りの動きをしない恐れのある特殊キー(BackSpace、Delete、Home、End、
PageUp、PageDownなどを含む)をまったく使わない操作が可能になっている。
# sshでリモート接続したときなどは特に、この操作体系がありがたい。
バッファ(クリップボードのようなもの)が使えたり、複数のファイルを
開けたりと、eeに比べれば格段に高機能なので、常用するかどうかは別として、
とりあえず一通りの操作を覚えておいて損はない(下記参照)。
http://www-lab.imr.edu/~ccms/Jpn/service/mint/vi/vi.htm
http://www.net-newbie.com/linux/commands/vi.html
emacsは「とにかくなんでもできる」エディタで、lisp派生のemacs lisp という
言語環境まで自前で持っている。xemacs、emacs21、muleなどの派生がある。
# 各派生ソフトウェアの関係については、筆者はよくわからない、
# というかemacs自体使ったことがない。
loader(8)のコマンド
# 起動直後の「boot -s」などを入力できる画面のこと。ごく一部だけ。
http://www.jp.freebsd.org/cgi/mroff.cgi?subdir=man&lc=1&cmd=&man=loader&dir=jpman-5.2.0%2Fman§=0
http://www.jp.freebsd.org/cgi/mroff.cgi?sect=8&cmd=&lc=1&subdir=man&dir=jpman-5.2.0%2Fman&subdir=man&man=loader.4th
boot カーネル名
カーネルを指定してブートする。
help トピック
/boot/loader.helpの内容を表示。目次から見たい場合は> help index もしくは
> ? とする。
lsとmore
シェルコマンドと同様。
lsdevとlsmod
モジュールがロード可能なデバイス/ロード済みのモジュールを表示。
loadとunload
モージュールのロードと全クリア。
include ファイル名
スクリプトファイルの実行。
setとunset
環境変数の指定と削除。
pnpscan
プラグアンドプレイデバイスのスキャン。FreeBSD5.2時点では未実装。
地味に便利なコマンドたち(手ごわくないものも含む)
http://x68000.q-e-d.net/~68user/unix/genre.html
システム情報
top
システム内の上位プロセスをリアルタイムで表示。何が重いのかわからないが
とにかくシステムが重いときに使ってみる。
vmstat
本来は仮想メモリの情報を表示するコマンドなのだろうが、CPUやディスクに
関する情報もわかる。情報は5秒ごとにサンプリングされているらしいので、
リアルタイムにモニタしたければ> vmstat -w 5 などとする。
lsvfs
現在ロードされている仮想ファイルシステムを表示。Linuxだと、シェルから
lsdevやlsmodが使えるものやlspciでPCIデバイスの一覧を表示できるものも
あるらしい。
df
ディスクの情報(容量など)を表示。
swapinfo
swap領域の情報を表示。書式はdfと同じ。
du ディレクトリ名
サブディレクトリの一覧を使用容量つきで表示。
ユーザー情報
id ユーザー名
ユーザーのuid、gid、所属するグループなどを表示する。ユーザー名を省略すると
自分の情報が出る。
who
ログインしているユーザーの一覧を表示する。
whoami
ユーザーIDを表示する。>idの方が情報が詳しい。
whois -h ドメイン管理元 メイン名
whoisデータベースを検索してドメインの所有者を調べる。
nslookup アドレス
ネームサーバに問い合わせてFQDNとIPアドレスの相互変換を行う。
ファイル/コマンド情報
man コマンド名
マニュアルを表示する。
file ファイル名
ファイルの種類を表示する。
what
ファイルを構成するオブジェクトモジュールのバージョンを表示する、らしい。
whatis
> man -f と同じ、らしい。
where コマンド
コマンドのフルパスを、重複したものも含めて優先順に表示する。csh系のコマンド。
whereis コマンド
コマンドのフルパスやman、src、portsなどのパスを表示する。
which
コマンドのフルパスを表示する。重複したものもはもっとも優先順位の高いもの
だけが表示される。
ldd コマンド
動的リンクによって依存しているファイルを表示する。
ファイル検索
find ディレクトリ名 検索対象 処理
指定ディレクトリ以下から検索対象を見つけて処理を実行する、と書くと意味が
わからないが、たとえば> find /usr/local -name myfile -ls とすると、
/usr/local以下から名前がmyfileのファイルもしくはディレクトリを探してパスなどを
表示する。単に> find myfile とした場合は、カレントディレクトリ以下からパス
(この場合は相対パスで指定しているので相対パス)にmyfileを含むファイルを
探して-printする。
# プライマリ(-nameとか-userとか)をひとつも指定しなかった場合、たとえば
# > find /usr/local myfile とした場合、なぜか絶対パスに/usr/localを含む
# ファイルと相対パスにmyfileを含むファイルを両方羅列する(/usr/local以下から
# myfileを含むファイルを探す、という挙動にはならない:FreeBSD4.9での動作)。
locate キーワード
インデックスファイル(/var/db/locate.database)を利用したファイル検索。
>locate キーワード で> find / -name '*キーワード*' -print とほぼ同じらしい。
インデックスファイルは/usr/libexec/locate.updatedbで更新できる(cronから
etc/periodic/weekly/のスクリプト経由で実行されている)。
文字列処理(文字コード除く)
tee
標準出力とパイプの両方に出力を流す。Teeという高機能版がある。
> command | tee ファイル1 ファイル2 などとして使う。
# 上記の例だと標準出力とファイル1とファイル2に出力される。
uniq ファイル
同じ行が連続する場合は1行にまとめて表示する。uniq -c ファイル で重複の
回数をカウントできる。
sort ファイル
ソート(辞書順もしくは数値の大小順に並べ替え)をして表示する。
> sort -u ファイル で重複行を1行にまとめて表示できる。+数字オプションで
ソートの対象とするフィールドを選択できる(>sort +2 ファイル 先頭から2つ
後ろのフィールドを対象にソート:数字が0から始まっていることに注意)が、
省略した場合は+0を指定したのと同じ扱いになる。
文字コード
coco
文字コードの判別。> cat ファイル名 | coco -q として使う。muleのコマンド。
iconv
文字コードの変換を行うが、たいていの場合nkfを使った方が楽。
> iconv -f 変換元コード -t 変換先コード < 変換元ファイル > 変換先ファイル
として使うらしい。
nkf
文字コードの変換をして標準出力に表示する。-jでJIS、-sでSJIS、-eでEUC-JPに変換。
ファイルに出力したい場合は> nkf -e 変換元 > 変換先 などとリダイレクトする。
qkc
文字コードの変換をしてファイルを書き換える。nkfと同じく-j、-s、-eの
オプションが使えるが、改行コードについても、-mでDos改行(CR+LF)に、-uで
Unix改行(LF)に、-maでMac改行(CR)に変換できる。-zオプションを使うと
ファイルの末尾の^Z(EOF)も削除できるらしい。
ちょっと変わったコマンドたち
Tee
teeの拡張バージョンで、受け取った入力を2つの出力に出力する。たとえば
> command | tee out.log
とすると、commandの出力を、標準出力とout.logファイルの両方に出力できる。
tac
デフォルトのFreeBSDにはインストールされていないコマンド(GNU coreutilsの一部)。
テキストファイルを最終行から順に読み出す(catの逆綴り)。
tailコマンドに-rオプション(GNUのtailには存在しないオプションらしい)をつけても
結果は同じだが、tacはファイル自体を反対から読むため、tailの仕様によっては
巨大ファイルに対する実行速度に差がつく場合がある。
# tailの-fオプション(ファイルをオープンし続け追記分を表示、リネームにも追従)や
# -Fオプション(監視対象ファイルがリネームされたら同じ名前のファイルを再度開く)
# なんかも非常に奥深い。
その他
wget URL(ファイルでもディレクトリでもOK)
HTTPとFTPに対応したダウンローダー。> wget -r -l 10 -N URL とすると、
10階層まで再帰的にリンクをたどって、新しいファイルだけを、URLから
ダウンロードしてくれる。fetchよりも高性能。ファイルはカレントディレクトリに
保存される。
talk
1対1でしか使えないチャットソフトのようなもの。
************************************************************
********** いいかげんなことばかり書いてあるので **********
********** 転んでも泣かない人専用! **********
************************************************************
apache(HTTP)
http://www.apache.jp/
http://httpd.apache.org/docs/
http://httpd.apache.org/docs-2.0/ja/
# どうしても必要でなければ、もっと軽いソフトウェアを使った方がよいと思う
本体インストール
http://hiiro-sou.hp.infoseek.co.jp/unix/server/apache.html
ports/www/apache13もしくはports/www/apache2をインストール。
/usr/local/etc/apache/httpd.confを適当に編集。待ち受けポートの番号、
管理者のメールアドレス、ドキュメントルート、ホストネームあたりが最低限の設定。
# portsを使わなかった場合、設定ファイルの場所が違うことがあるらしい
# ホストネームは、最後の/を省略してディレクトリにアクセスした場合に
# リダイレクト先URLの一部になるようなので、書かなくても動くからといって
# 設定を省略しない(外からアクセスする場合に使うドメイン名を書く)。
ディレクトリのオプションは、とりあえずすべてNoneにしておくのが無難だろう。
mod_include、mod_cgi、mod_proxyなど、不要なモジュールは読み込みを止めておく。
# LoadModuleとAddModuleの部分をコメントアウトする。
設定ファイルの詳細
http://warp.syns.net/2/3/
http://www.unix-power.jp/linux/redhat/apache.html
http://www.mikeneko.ne.jp/~lab/web/htaccess/
http://mononoke.dyndns.org/~kamada/freebsd/freebsdmain.htm
# apache1.3の場合。2.x系でもそれほど大きくは変わらないと思う。
ディレクトリやファイルの設定書式は<カテゴリ>とカテゴリ>の間に命令を
書くようになっており、たとえば
Options MultiViews
AllowOverride None
とあれば、ドキュメントルートからの相対パスが/cgi-binであるディレクトリで、
MultiViewsオプションを有効にして、.htaccessファイルでの上書きは禁止する、
という意味になる。
# たとえばドキュメントルートが/usr/local/www/dataである場合、
# は/usr/local/www/data/cgi-binを指す。
# ダブルクォーテーションでくくると絶対パスでの指定になるらしいので、
# としても同じ意味(のはず)。
のようにワイルドカードの利用も可能
DirectoryではなくDirectoryMatchで指定すると、拡張正規表現と呼ばれる
本格的な正規表現が使える。
# のようにチルダを挟んでも、
# DirectoryMatchを使った場合と同様に拡張正規表現が使えるが、
# これは歴史的な経緯らしく、どちらでも問題ないようだ
# 一般に拡張正規表現を使う場合はダブルクォーテーションでくくる模様。
ファイル指定の場合などとFilesで指定する。
# 上記は拡張子が.cgiであるファイルすべてという意味
# これもチルダを挟むかFilesMatchで指定すると拡張正規表現が使える
また、Optionsは有効にするものを+、無効にするものを-で表し、たとえば
Options +Indexes -FollowSymLinks +Includes
などと書くのが本来の書き方のようだ。
# +や-を省略した場合先頭に書いたもののみが有効になる。
# とりあえずすべて明示的に書いておくのが無難だろう。
この他にAllowとDenyでアクセス制御が設定でき、
Allow ホスト名 とかDeny ホスト名 などとする。
# 指定方法は、ホスト名(.で始めると前方一致)、IPアドレス(.で終わると後方一致)、
# サブネットマスクつきIPアドレス、allなど。
さらにOrderを指定してAllowとDenyの優先順序を決める。
# deny,allowはデフォルト許可>deny指定されたものを拒否>拒否された
# もののうちallow指定されたものを改めて許可、allow,denyだとデフォルト拒否>
# allow指定されたものを許可>許可されたもののうちdeny指定されたものを
# 改めて拒否、mutual-failureだとallow指定されていてかつdeny指定されていない
# ものを許可、ということになるが、allow,denyとmutual-failureは結局
# 同じ意味になる(書き方としてはallow,denyが推奨らしい)
モジュールのインストール
# portsのwwwセクションに入っているモジュールもあるが、
# ソースからのインストールも非常に楽なのでどちらでもよい。
# 以下はソースからのインストールについて。
欲しいモジュールのソースコードを入手して解凍する
# モジュール名+ダウンロードあたりでぐぐればすぐ見つかるはず。
# たとえばmod_perlならhttp://perl.apache.org/からDownloadを選べばよい
展開時にできたディレクトリにC言語のソースコードがあるはず。
ソースコードを展開したディレクトリで
> apxs -c C言語ソース
でモジュールのコンパイル
# 例 > apxs -c mod_perl.c
# これでカレントディレクトリにmod_perl.soとmod_perl.oができる
> apxs -i -a モジュールファイル(.so)
でモジュールを有効にしてくれる
# 例 > apxs -i -a mod_perl.so
# これで/usr/local/libexec/apache以下にmod_perl.soがコピーされ、
# httpd.confも自動で更新される(バックアップも取ってくれるが、
# 一応手動でもバックアップしておいた方がよいだろう)
あとは
> apachectl graceful
でやさしく再起動してやれば動くはず。
管理
メールのエイリアスを変更(その8のpostfixの項目を参照)し、webmaster宛てと
www宛てのメールがrootに届くようにしておく。
# FreeBSDデフォルトの設定ファイルを使っているなら、
# SUPPORT MAILBOX NAMES FOR SPECIFIC INTERNET SERVER という項目の
# コメントを外すだけでよい
ログローテーションの際、1番ではなく30番のシグナルで再起動する
ことになっているので注意が必要。
# apachectlの引数でいうと、restartではなくgracefulを使うということ。
その他
semdmailやwu-FTPDも、機会があれば(話のネタに)触ってみたいがちょっと怖い。
シェルスクリプトの作成(オマケ)
http://naoya.dyndns.org/doc/script_howto.txt
http://www15.big.or.jp/~yamamori/sun/boot/shell.html
http://x68000.q-e-d.net/~68user/unix/pickup?test
http://x68000.q-e-d.net/~68user/unix/pickup?%A5%B7%A5%A7%A5%EB%A5%B9%A5%AF%A5%EA%A5%D7%A5%C8
http://www.jp.freebsd.org/cgi/mroff.cgi?subdir=man&lc=1&cmd=&man=sh&dir=jpman-5.2.0%2Fman§=0
http://www.jp.freebsd.org/cgi/mroff.cgi?subdir=man&lc=1&cmd=&man=test&dir=jpman-5.2.0%2Fman§=0
http://warp.syns.net/10/index.html
文法
# 基本的にインタープリタとなるシェルのコマンドラインと同じ。
# シェルで使える正規表現も同様に使える。
1行目はインタープリタ行で、#! /bin/sh などと、シャープ、エクスクラメーション、
スペースに続けて、コマンドを実行するインタープリタを指定する。
shの代わりにtcshなどを使ってもよいが、shを使っておくのが無難。
# 以下ではshを使うものとして話しを進める。
変数はVARIABLE=valueの形で設定し、${VARIABLE}という形で呼び出す。
$0や$1は引数を表し、$0には実行中のスクリプトの絶対パスが入っている。たとえば
> /tmp/myscript.sh arg1 arg2
とした場合、/tmp/myscript.shが$0、arg1が$1、arg2が$2の値になる。
$?は最後に実行したコマンドからの戻り値を表し、$#は引数の個数を表す。
ダブルクオーテーションで囲った部分はひとまとまりの入力として扱われるが、
変数は展開(代入)される。シングルクオーテーションで囲った部分も
ひとまとまりの入力として扱われるが、変数が展開されない(文字通りに解釈される)。
プライム記号で囲った部分には、コマンドの実行結果(出力)が代入される。
# ASCIIではシングルクォートとアポストロフィが0x27の「'」で
# 逆クォートが0x60の「`」という扱いだが、もともとは「`'」でワンセットの
# シングルクォーテーションだったとか、もっと前は
# 「`」がグレイヴアクセント(アクサングラーヴ)で「'」がアポストロフィだったのを
# シングルクォーテーションに代用しただけだとか、諸説あってよくわかんない。
たとえば、(#!で始まる行はコメントではなくインタープリタ行)
#! /bin/sh
VARIABLE=value
echo "${VARIABLE}"
echo '${VARIABLE}'
echo "`basename $0` $1"
という内容で/tmp/myscript.shを作成し、chmodで実行権限を与えてから
> /tmp/myscript.sh arg
として実行した場合、画面には
value
${VARIABLE}
myscript.sh arg
と表示されるはず。
# basenameは、文字列から最後のスラッシュより後ろの部分を抜き出すコマンド。
ちなみに、
echo aada ; kouda
と書いてしまうと(シェルで> echo aada ; kouda としたのと同じことになり)、
echoコマンドがaadaという文字列を表示した後koudaコマンドを実行しようとする。
echo "aada;kouda"
としておけば、画面にaada;koudaという文字列が表示される。
# 常にダブルクォーテーションを使うクセをつけておくとよい。
分岐
case文による分岐は
case "変数" in
パターン1)
;;
パターン2)
;;
以下分岐が終わるまで繰り返し
esac
という流れになる。最初のcase "変数" in の部分は、もし変数が以下の値なら、
という意味。パターンの部分では、変数の値がパターンに一致すれば次の行に進み、
一致しなければ次の値分岐まで読み飛ばす。;;の行を読むとesacの行まで読み飛ばす。
# ;;の行はパターンによる分岐が終わるたびに必ず必要。
たとえば、(便宜上行番号を振ったが、実際のスクリプトではこのように書かない)
1 case "$1" in
2 arg1)
3 echo "arg=1"
4 ;;
5 arg2)
6 echo "arg=2"
7 ;;
9 arg3)
10 echo "arg=3"
11 ;;
12 esac
という内容で/tmp/myscript.shを作成し、chmodで実行権限を与えてから
> /tmp/myscript.sh arg2
とすると、2行目を読んだ時点で$1の値がarg1ではないので5行目に進み、
5行目を読んだ時点で$1の値がarg2なので6行目に進み、6行目のコマンドを実行し、
7行目を読んで指示どおり12行目に進む。
# 想定していない値が入っていた場合にエラートラップするなら、
# *)
# echo "error"
# ;;
# などといった分岐を最後に付け加えておく。
if文による分岐は
if コマンド
then
then文による分岐の処理
else
else文による分岐の処理
fi
という流れになり、ifの後に続けて書いたコマンドを実行して、戻り値が
0ならthen以下、0以外ならelse以下を実行した後、fiまで読み飛ばす。
else文はなくてもよい。
# testコマンドと組み合わせて使うことがほとんど(下記参照)。
# http://www.jp.freebsd.org/cgi/mroff.cgi?subdir=man&lc=1&cmd=&man=test&dir=jpman-5.2.0%2Fman§=0
終了と戻り値
最後の行まで実行すると最後に実行したプロセス(上記の例だと、echoコマンド)が
返した戻り値をそのまま保持して($?を書き換えることなく)終了するが、
exit 戻り値
と書いておけば、その行を読んだ時点で指定した戻り値を返して終了する。
# exitとだけ書く(戻り値を省略する)と、$?を書き換えることなく終了する。
終了後にシェルから
> echo $?
とすれば、戻り値を確認できる。たとえば戻り値5でエラー終了した場合、
スクリプトをエディタで開いてexit 5 を検索すれば、どこでエラーが起きたのか
把握できる(エラー終了時にきちんとした戻り値を返すようになっていなければ
意味がないし、エラーメッセージを吐くようにした方が恐らく手っ取り早いが)。
起動のみ
# 凝ったことをしないのなら、たいていの場合これだけで事足りる
以下の2行だけでよい。
#! /bin/sh
実行するコマンドを絶対パスで書く
# 出力を捨てる場合は、コマンド > /dev/null 2>&1 としておく。
たとえば/usr/libexec/ftpdを-Dオプションつきで実行するなら、
#! /bin/sh
/usr/libexec/ftpd -D
とする。
コマンドが存在しないときのエラートラップ
testコマンドを利用して、
#! /bin/sh
if test -x コマンドの絶対パス
then
コマンドの絶対パス
else
異常終了処理
fi
などとする。
# ファイルの存在を調べるなら-f、実行可能かどうかまで調べるなら-xオプション
# を使う。また、[ -x コマンドの絶対パス ]; then と書いても同じ意味になる。
異常終了処理は、
echo "error" >&2
などとエラーメッセージを吐いておく。
スタート、ストップ、再起動で分ける
case分岐を使って
#! /bin/sh
case "$1" in
start)
開始処理
;;
stop)
終了処理
;;
restart)
再起動処理
;;
*)
定義していない引数の処理
;;
esac
などとする。
終了処理は、たとえば、
/bin/kill `cat pidファイルの絶対パス`
# pidファイルは、デーモンが自分のPIDを書き込む拡張子.pidのファイルのことで
# 普通は/var/run/以下だが、たとえばapacheならhttpd.confのPidFileという行で
# 変更できる
などとする(pidファイルがない場合はpsコマンドを使う)。
再起動処理は、たとえば、
/bin/kill -1 `cat pidファイルの絶対パス`
もしくは
/bin/kill -s HUP `cat pidファイルの絶対パス`
として1番(HUP)のシグナルを送ってやればよい。
# 上の2つのコマンドはどちらも同じ意味。
定義していない引数の処理は、たとえば
echo "Usage: `basename $0` {start|stop}" >&2
もしくは
echo "invalid argument" >&2
などとしてエラーメッセージを吐いたうえで
exit 64
などとして終了する。
# exit時の戻り値は、(portsで入れたときの起動スクリプトに64と
# しているものが多いので)とりあえず64としているが、本来は
# 違う値を返すのかもしれないし、2以上ならいくつでもよいのかもしれない。
# もしかすると1でもいいのかも(ようするに筆者はわかっていない)。
結局のところ
#! /bin/sh
case "$1" in
start)
if [ -x コマンドの絶対パス ]; then
コマンドの絶対パス
else
echo "Command not found or permission error" >&2
fi
;;
stop)
if [ -r pidファイルの絶対パス ]; then
/bin/kill `cat pidファイルの絶対パス`
else
echo "PIDfile not found or permission error" >&2
fi
;;
restart)
if [ -r pidファイルの絶対パス ]; then
/bin/kill -s HUP `cat pidファイルの絶対パス`
else
echo "PIDfile not found or permission error" >&2
fi
if [ -x コマンドの絶対パス ]; then
コマンドの絶対パス
else
echo "Command not found or permission error" >&2
fi
;;
*)
echo "Usage: `basename $0` {start|stop|restart}" >&2
;;
esac
などとすればよいことになる(はず)。
# エラーメッセージを吐いていることだし、エラー時の戻り値は設定しなかった。
さらにエラートラップをしつこくやるなら、コマンド実行の部分を
if コマンドの絶対パス
then
終了処理
else
エラー処理
fi
としておけばよい・・・と思ったのだが、よくない書き方らしいので、
コマンドの絶対パス
STATUS="$?"
if [ ${STATUS} eq 0 ]; then
終了処理
else
エラー処理
fi
とでもすればよいだろう。
特殊な変数のまとめ
$数字 引数を番号で示す
$# 引数の個数
$@と$* $0以外の全ての引数
$? 最後に実行したコマンドの返した戻り値
$! 最後に実行したバックグラウンドコマンドのPID
$$ スクリプトを実行しているシェルのPID
$- 現在のオプションフラグ
$@と$*では展開のされ方が違い、$1=hoge、$2=moge、$3=pogeとなっている場合、
"$*"は"hoge moge poge"、"$@"は"hoge" "moge" "poge"と解釈される
(クォーテーションで囲わなかった場合はどちらもhoge moge poge で同じ)。
利用可能なシェル組み込みコマンドの一覧
http://www.jp.freebsd.org/cgi/mroff.cgi?subdir=man&lc=1&cmd=&man=while&dir=jpman-5.2.0%2Fman§=0
http://www.jp.freebsd.org/cgi/mroff.cgi?sect=1&cmd=&lc=1&subdir=man&dir=jpman-5.2.0%2Fman&subdir=man&man=csh
http://www.jp.freebsd.org/cgi/mroff.cgi?sect=1&cmd=&lc=1&subdir=man&dir=jpman-5.2.0%2Fman&subdir=man&man=sh
コマンド 外部 csh(1) sh(1)
alias Yes Yes Yes
alloc No Yes No
bg Yes Yes Yes
bind No No Yes
bindkey No Yes No
break No Yes Yes
breaksw No Yes No
builtins No Yes No
case No Yes Yes
cd Yes Yes Yes
chdir No Yes Yes
command Yes No Yes
complete No Yes No
continue No Yes Yes
default No Yes No
dirs No Yes No
do No No Yes
done No No Yes
echo Yes Yes Yes
echotc No Yes No
elif No No Yes
else No Yes Yes
end No Yes No
endif No Yes No
endsw No Yes No
esac No No Yes
eval No Yes Yes
exec No Yes Yes
exit No Yes Yes
export No No Yes
false Yes No Yes
fc Yes No Yes
fg Yes Yes Yes
filetest No Yes No
fi No No Yes
for No No Yes
foreach No Yes No
getopts Yes No Yes
glob No Yes No
goto No Yes No
hash No No Yes
hashstat No Yes No
history No Yes No
hup No Yes No
if No Yes Yes
jobid No No Yes
jobs Yes Yes Yes
kill Yes Yes No
limit No Yes No
log No Yes No
login Yes Yes No
logout No Yes No
ls-F No Yes No
nice Yes Yes No
nohup Yes Yes No
notify No Yes No
onintr No Yes No
popd No Yes No
printenv Yes Yes No
pushd No Yes No
pwd Yes No Yes
read Yes No Yes
readonly No No Yes
rehash No Yes No
repeat No Yes No
sched No Yes No
set No Yes Yes
setenv No Yes No
settc No Yes No
setty No Yes No
setvar No No Yes
shift No Yes Yes
source No Yes No
stop No Yes No
suspend No Yes No
switch No Yes No
telltc No Yes No
test Yes No Yes
then No No Yes
time Yes Yes No
trap No No Yes
true Yes No Yes
type No No Yes
ulimit No No Yes
umask Yes Yes Yes
unalias Yes Yes Yes
uncompleteNo Yes No
unhash No Yes No
unlimit No Yes No
unset No Yes Yes
unsetenv No Yes No
until No No Yes
wait Yes Yes Yes
where No Yes No
which Yes Yes No
while No Yes Yes