改訂版 シェルスクリプトについて ( ports 編 )
id:otsune 様が test(1) なんて不思議な man を言っていたので見てみました。
まさかこんな罠があるなんて・・・勉強不足なだけとか言わない。
先日のエントリーで関連のある項目を抜き出してみました。
-x file True if file exists and is executable. True indicates only that the execute flag is on. If file is a directory, true indicates that file can be searched. ! expression True if expression is false.
以下は日本語マニュアルからです。
-x file file が存在し、実行可能であれば真になります。真ということ は、実行可能フラグが立っていることを表すに過ぎません。 file がディレクトリの場合、真は file が検索可能であることを表し ます。 ! expression expression が偽ならば真になります。
以下の構文は先日のエントリーの問題だった箇所から。
[ ! -x /usr/local/sbin/portsnap ] && exit 0
&& は 倫理積 論理積 ( 2006/07/09 追記:倫理積ではなく、論理積です。すいませんでした。コメントをくださった kogule 様、ありがとうございました。 ) らしいので条件に当てはまる場合には exit に 0 を返す、つまりシェルスクリプトをその場で終了って事ですね。
この 倫理積 論理積とかの言い回しがややこしくて脳内フィルターかけていないと、理解するどころか何を言ってるのがわかりません。
そんなヘタレだからなかなか進歩しないんでしょうけど。 :-)
次の問題の箇所は下記の通り。 ( 抜粋 )
echo echo "Ports/packages update check:" (portsnap cron && portsnap update) >/dev/null 2>&1 if [ $? -eq 0 ]; then portsdb -u >/dev/null 2>&1 portversion -vL= rc=0 else echo "Failure of portsnap(*ERROR*)" rc=1 fi echo
まず上記の条件分岐ですが、これは $? を読み間違えていたことからおかしくなったんだと思います。
$? という変数は最後に実行したコマンドの exit 値を返します。
例えば下記のようなシェルスクリプトを組んだ場合、カレントディレクトリが表示されます。
#!/bin/sh cd ~/ if [ $? -eq 0 ]; then pwd rc=0 else echo "hoge" rc=1 fi exit $rc
-eqは条件の評価のひとつで、上記の例だと $? が 0 と等しい場合はそのまま実行する、ということになります。
上記でも解説しましたが、 $? は最後に実行した exit 値を持っています。
このシェルスクリプトでは cd ~/ となっいて、正常終了したので $? の値は 0 です。
まとめると、 $? は 0 と等しいのでそのまま構文を続ける、ということにます。
では上記のことを踏まえた上で id:hiro-ueda 様のシェルスクリプトに戻ってみましょう。
今度は全文掲載です。
( id:hiro-ueda 様からは教材として使用する許可をもらいました。 id:hiro-ueda 様、ありがとうございます。 )
#!/bin/sh # # $Id: 499.status-pkgupdate,v 1.2 2005/08/01 02:15:07 ueda Exp $ # # If there is a global system configuration file, suck it in. # if [ -r /etc/defaults/periodic.conf ] then . /etc/defaults/periodic.conf source_periodic_confs fi export PATH=$PATH:/usr/local/sbin:/usr/local/bin export LANG=C [ ! -x /usr/local/sbin/portsnap ] && exit 0 echo echo "Ports/packages update check:" (portsnap cron && portsnap update) >/dev/null 2>&1 if [ $? -eq 0 ]; then portsdb -u >/dev/null 2>&1 portversion -vL= rc=0 else echo "Failure of portsnap(*ERROR*)" rc=1 fi echo exit $rc
まずは上から順に読み解いていきます。
なお、コメント行には触れません。
#!/bin/sh
どのシェルを使うのか指定する。
if [ -r /etc/defaults/periodic.conf ] then . /etc/defaults/periodic.conf source_periodic_confs fi
test(1) を見てみる。
-r file file が存在し、それが読み込み可能であれば真になります。
なので、先日のエントリーも微妙に間違っていたかも。
とりあえず『おまじない』と考えておけばいいと思います。 ( ダメ? )
export PATH=$PATH:/usr/local/sbin:/usr/local/bin export LANG=C
これはそのまま。
環境変数とロケールを通しています。
( /bin/tcsh の場合は export が setenv になる。 ( はず ) )
[ ! -x /usr/local/sbin/portsnap ] && exit 0
上記で解説した通り。
if [ $? -eq 0 ]; then portsdb -u >/dev/null 2>&1 portversion -vL= rc=0 else echo "Failure of portsnap(*ERROR*)" rc=1 fi echo exit $rc
これでも上記で解説した通り。
$rc については昨日の解説でほぼ間違いないと思います。
とりあえずこんな感じでしょうか。
昨日の敗因をまとめると、
・シェルスクリプトの構文をひとつひとつ読み解いていった事。
・exit 値を何かと勘違いしていた事。
こんな感じだと思います。
そして今後の方針のまとめとして、
・シェルスクリプトに限らず、まずは上から下まで構文を読み取った上で、解説する時には関連項目 ( 参考文献や man など ) を一緒に提示する。
・諦めない心。 ( ぉ
意外と他の言語に共通するものがあるのでこういった所から入っていけば案外 C も独学でいけそうな気がしてきました。
余談ですが、『 man [ 』なんて使い方があるなんて思ってもいませんでした。
多分純正のゲイツ様に教育された Windows 使いが何故 Unix を敬遠するのか少しわかった気がします。
・・・違う?