(2008年度) 学生実験1 : スクリプトプログラミング






更新情報
  • [2008-05-07] 昨年度の資料参考文献/サイトを参考に,コンテンツと課題を作成し直しました.
  • [2008-05-12] リング切れを修正しました.1.9節(gnupplot の利用)を追加しました.
  • [2008-05-19] Level7を明記しました.条件0を追加してあるので注意してください.
  • [2008-05-19] 事前準備にEasyPackageでインストールする際の注記を追加しました.







実験の進め方

内容と達成目標

今回のテーマ「スクリプトプログラミング」では,「そもそもそんなコマンドがあること自体知らなかった」「作業を自動化するためのポインタが分からなかった」等の理由でこれまで機械的な作業を手作業でやっていた仕事(の一部)を自動化する事が目標です.具体的には以下の通り.

  • 達成目標1:シェル(sh/bash)上での正規表現を理解し,使えるようになる.
  • 達成目標2:シェルで繰り返し作業を使えるようになる.
  • 達成目標3:(シェルで簡単なログ解析をスクリプトで組み),その結果を gnuplot でグラフ作成できるようになる.

コメント

今回の内容に限らず,講義/実験でやった内容は何らかの形でサマリや例題を残す等して,忘れたときに「ここを見れば分かる!」というノートを作成するようにしましょう(今回の実験では,作成したスクリプト内に適切にコメントを書いておけば,そのときとある動作をどのように実現したのかが分かり,作業記録としても使えます).

また,適宜参考文献や google を駆使し,様々な利用例を読み,実行しなくては自由自在に操れるようにはなれません. シェルスクリプトに限らず,Perl/PHP/Ruby/Pythonなど,様々なスクリプト言語がありますので,時間のあるときにでもそれらについても調べてみてください.

進め方
  • テキスト・補助教材:本ページや参考文献参照(サンプルソースもあります)
  • 作業スタイル:個人作業(1人1レポート)
評価基準

レポートでは指定した課題をこなしている(提出している)事を前提に基準点(50点程度)を設け,以下の項目に沿って加点・減点を行う. 特に,テーマに関連する事柄を自主的にやってきた場合には積極的に加点対象対称として採点するので,各自創意工夫して自主課題に取り組む事.

加点
  • 独自に行った関連課題に関する報告(積極性).
  • 実験中に示した手法ではなく,自力で探し出した異なる手法で問題を解決した場合(積極性・実践性・創造性).
  • 手法の利点・欠点や限界等に関して自主的にトライした結果・考察が示されている場合(積極性・専門性).
  • レポートの見せ方に関する工夫など(コミュニケーション能力).
  • その他,本テーマに関連する実験的側面上「積極性・実践性・創造性・コミュニケーション能力」等の観点から評価できるもの.
減点
  • 先行研究や事例,レポート,web等を参照しているにも関わらず,それらを参考文献として参照していない場合(一般倫理).
  • 論理的矛盾が見られる場合(論理性).
  • 結果を示さずに考察のみを記載してたり,結果に対する考察に整合性が見られない場合(コミュニケーション能力).
  • タイプミスや可読性の欠如,数式等記号の印字ミス,提出期限の遅れ等,多方面に関して大きな誤りではない場合.

課題と提出方法
  • 1人1レポート提出.
  • Level1 から Level7 にトライし,レポートとしてまとめよ.
  • 2章以降(Level8以降)は全てオプション課題であり,独自に設定した自主課題も含めてやるやらないは任意である.
  • 本文とは分けて表紙を作成する事.表紙には以下の項目を記述すること.
    • 実験テーマ名,担当教員名
    • 氏名,学籍番号
    • 実験日,提出期限日,提出した日
  • オリジナル課題に取り組んだ場合には,その課題設定を解説した上で過程・結果・考察等をまとめる事.
  • 提出物
    • [提出物1] レポートは LaTeX で作成し,PDFファイルとして作成する事.提出物には LaTeX ファイル一式(tex, eps ファイル等全て)を含む事.ファイル名の例:e0757xx.pdf
    • [提出物2] 作成したスクリプト一式
  • 上記2点を naha にアップロードし,tnal@ie.u-ryukyu.ac.jp 宛に以下のタイトルで報告メールを送信する事.報告メールが無い場合には減点となります(ホウレンソウ)

    火曜日のクラス
    →Subject: (info1/shell/tue) e0765x
    
    金曜日のクラス
    →Subject: (info1/shell/fri) e0765x
    


    (アップロード例) 以下は ~/jikken1/shell/ に提出物を保存している場合の例です. 修正する場合も同じコマンドで構いませんが,アカウント名(e0757xx)を間違えないように注意する事! rsync 自体の説明は例えばここを参照してください.

    % cd   (ホームディレクトリに移動)
    % rsync  -auve  ssh \
       ~/jikken1/shell/ \
       e0757xx@naha:/home/teacher/tnal/jikken1-tue/e0757xx/
    % rsync  -auve  ssh \
       ~/jikken1/shell/ \
       e0757xx@naha:/home/teacher/tnal/jikken1-fri/e0757xx/
    
  • 提出期限:実験日の10日後まで(5/16のクラスの期限は5/26,5/20のクラスは5/30).


0. 事前準備

  1. Mac OS X 側の準備
    1. X11.appをインストール(参考:X Window System).
    2. EasyPackageのmath/gnuplot(gnuplot+), graphics/ImageMagickをインストール.必要に応じて japanese/tgif も.

      EasyPackageでのインストールの仕方はここのFAQを参照の事.徳に,EasyPackage本体のバージョンが古いと,インストールされるパッケージが古いままだったり,インストール自体できない等のトラブルが生じやすいので必ず最新版にアップデートするようにしてください.

    3. 各種アプリの動作確認.
      • gnuplot参考:gnuplot入門(今回は数値データをプロットし,印刷(画像ファイルとして保存)できればOK)
      • ImageMagick参考:Imagemaagickの使い方(今回はconvertが使えればOK)
  2. Linux (cls0xx) 側の準備
    1. gnuplot をインストール(参考:yumとは?).
      MacBook-X11# ssh -X cls001    #クラスタにログイン
      cls001# which gnuplot      #gnuplotがインストールされているかを確認
      cls001# sudo yum install gnuplot #yum でパッケージインストール
      
    2. ImageMagick をインストール.やり方は上記参照.
    3. 各種アプリの動作確認.

各アプリケーションの説明は参考文献・サイトを参照.


1. shell script の基礎

C/Java等のコンパイラ言語で書くほどではないが

  • 日頃良く使う一連のコマンド群をより簡単に実行したい
  • 複数のファイル/ディレクトリに対して同一の処理を実行したい
  • 自動化したい
等,コンピュータにちょっとした仕事をやらせる方法の一つとして「スクリプト言語 / 軽量プログラミング言語(Lightweight Language, LL)」を利用したプログラミングがある.具体的な例としては,Perl や PHP を使った WWW 上の掲示板のような目に見えやすいものから,OSの起動処理など,探してみると実に様々な箇所でスクリプト言語が利用されている. 今回は,LL と比べると非力ではあるが,スクリプト言語の基本的な考え方を学ぶために多くの Unix 系 OS のデフォルトシェルとして利用されている sh (bash) シェルを利用したシェルスクリプトの作成方法について学ぶ.



1.1. bash シェルの実行

今回使用するシェルは「/bin/sh (Borne Shell)」です.
正しくパスが設定されているならば,「sh」と入力しただけでも /bin/sh を起動することが出来ますが,念のために以下のようにして実行ファイルの場所とバージョンを出力確認してください.
ここで,/bin/sh 以外のパスが出力されたり,tcsh/zsh 等異なるシェル名が出力されたら,alias や .tcshrc/.bashrc 等の設定を確認してみてください.

% which sh     # sh のある場所を確認
% sh --version # sh のバージョン確認

GNU bash であることが確認できたら,sh を実行しましょう.

% sh
sh-2.05b$      # <--プロンプトが変わっているのを確認
sh-2.05b$ exit # exit でシェルを終了できます
% 

1.2. シェル変数への値の代入と参照

C言語の場合,1+2 の結果を計算し,結果を確認するためには例えば以下のようなソースを書くことになります.(ここでは include や main() は省いています)

# C言語での 1+2 の例
int a, b, c;
a = 1; b = 2;
c = a + b;
printf("c=%d\n",c);
同様のことをシェルで実行するには以下のように書きます.
# (例1.2) シェルスクリプトでの 1+2 の例
# sh を起動した状態で入力してください
a=1
b=2
c=`expr $a + $b`
echo c=$c
ポイント
  • 変数に値を代入するにはname=valueという形式で書く(=の前後にスペースがあるとNG!).
  • 変数を宣言する必要は無い.
  • int や char といった値の型を宣言する必要も無い.
  • 参照時には$nameまたは${name}として$を頭に付ける必要がある.
  • printf() のような出力にはechoを使う.
  • `バック・クォーテーション`で囲うと,その実行結果に置き換えられる.
  • exprコマンドで四則演算が可能(演算子の前後にスペース必須).

1.3. 特殊文字の利用(エスケープシーケンス)

変数には任意の文字列を代入できますが,一部の特殊文字(; & ( ) | ^ < > ? * [ ] $ ` " ' { } [TAB] [SPACE])は,そのままでは代入することが出来ません.これらの特殊文字を「ただの文字」として使うにはエスケープシーケンスにより表現する必要があります.

# (例1.3) エスケープの例
$ a=This is example
sh: is: command not found
$ a=This\ is example
sh: example: command not found
$ a=This\ is\ example
$ echo $a
This is example

$ a="This is example"
$ echo $a
This is example

$ b=1
$ c="$a, b=$b"
$ echo $c
This is example, b=1

$ c='$a, b=$b'
$ echo $c
$a, b=$b

$ c="$a, b=\$b"
$ echo $c
This is example, b=$b

ポイント
  • [SPACE] は区切り文字とみなされる.
  • バックスラッシュ(\)は,次に続く1文字をただの文字とみなす.
  • ダブル・クォーテーション("hoge")によるエスケープでは,変数($value),バック・クォーテーション(`hoge`),バックスラッシュ(\)以外をただの文字とみなす.
  • シングル・クォーテーション('hoge')によるエスケープでは,全ての特殊文字がただの文字としてみなされる.

1.4. シェルスクリプト(スクリプトファイル)の作成と実行

例1(シェルスクリプトでの 1+2 の例)をシェルスクリプトとして利用するには,以下のように記載されたファイルを作成し,実行する.

#!/bin/sh
# (例1.4) シェルスクリプトの例: example2.sh
a=1
b=2
c=`expr $a + $b`
echo c=$c

スクリプトファイルの実行方法は2通りある.
1つ目は,ファイルに対して実行許可を与え,ls 等のコマンドと同様にファイル名を実行ファイル名として利用する.
2つ目は,シェルに対する引数としてファイルを指定して実行する.

# (例1.4.1) 1つ目の実行方法
$ ls -l example2.sh
-rw-r--r--   1 tnal  tnal  49 Jun  5 22:15 example2.sh
$ chmod u+x example2.sh
-rwxr--r--   1 tnal  tnal  49 Jun  5 22:15 example2.sh
$ ./example2.sh
c=3


# (例1.4.2) 2つ目の実行方法
$ sh example2.sh
c=3
Level1: 以下の機能を満たすシェルスクリプト (level1.sh) を作成せよ.
  • a=6, b=3 とし,四則演算を計算する.
  • 実行結果は以下のように出力すること.
    prompt> ./level1.sh
    
    # Level1の実行結果
    a=6, b=3
    a+b=9
    a-b=3
    a*b=18
    a/b=2
    
    prompt>
    

1.5. 特殊な変数

先の例で見た通り,変数を参照する際にはname=valueとして値を設定後に$nameとして参照する. 表1.5 に示す変数はシェルスクリプト実行時に自動的にセットされている(手動で設定する必要が無い)特殊な変数である.

表1.5. 特殊な変数
$0スクリプトの名前
$1,$2, ..., $9スクリプトに渡されたx番目の引数
$#スクリプトに渡された引数の個数
$*スクリプトに渡された全引数のリスト

#!/bin/sh
# (例1.5) 特殊変数の利用例: example1.5.sh
echo "The number of arguments : $#"
echo "The name of this script : $0"
echo "The first argument      : $1"
echo "The second argument     : $2"
echo "All of argumtns         : $*"
echo "Process ID              : $$"

# 実行例
sh-2.05b$ ./example1.5.sh 1 2 3 4 
The number of arguments : 4
The name of this script : ./example1.5.sh
The first argument      : 1
The second argument     : 2
All of argumtns         : 1 2 3 4
Process ID              : 2548
sh-2.05b$ 
Level2: 以下の機能を満たすシェルスクリプト (level2.sh) を作成せよ.
  • level1.sh を拡張(複製して新しくファイルを作成)する.
  • level1.sh では演算対象の a,b をスクリプト内で設定していたが,この2つの値を実行時の引数から設定するようにする.
  • 実行結果は以下のように出力すること.以下では2例示しているが,重要なのは変数 a,b をスクリプトへの引数として実行時に指定できるようにする事である.
prompt> ./level2.sh 8 2

# 参考出力結果(Level2)
a=8, b=2
a+b=10
a-b=6
a*b=16
a/b=4

prompt> ./level2.sh 10 5

# 参考出力結果(Level2)
a=10, b=5
a+b=15
a-b=5
a*b=50
a/b=2

prompt>

1.6. 条件分岐(if, case, [])

シェルスクリプト中では if, case を使った条件分岐が可能で以下のような比較演算子(文字列)が記述可能である.標準的な書式としては以下のように記述される.

#!/bin/sh
# (例1.6.1) if文の例: example1.6.1.sh
#引数チェック例
if [ $# -eq 2 ] ; then
    str1=$1
    str2=$2
else
    echo "Usage: prompt> $0 arg1 arg2"
    exit 1
fi

#文字列比較例
echo "str1=$str1, str2=$str2"
if [ $str1 = $str2 ] ; then
    echo "str1 = str2"
else
    echo "str1 != str2"
fi

#実行例
prompt> ./example1.6.1.sh
Usage: prompt> ./example1.6.1.sh arg1 arg2
prompt> ./example1.6.1.sh hoge fuga
str1=hoge, str2=fuga
str1 != str2

#!/bin/sh
# (例1.6.2) case 文の例: example1.6.2.sh
if [ $# -eq 1 ] ; then
  str1="$1"
else
  echo "Usage: prompt> $0 arg1"
  exit 1
fi

case $str1 in
  hoge)
    echo "str1=hoge"
    ;;
  fuga)
    echo "str1=fuga"
    ;;
  *)
    echo "str1 has bad value (str1=$str1)."
    exit 1
esac

#実行例
sh-2.05b$ ./example1.6.2.sh     
Usage: prompt> ./example1.6.2.sh arg1
sh-2.05b$ ./example1.6.2.sh fuga
str1=fuga
sh-2.05b$ ./example1.6.2.sh 1   
str1 has bad value (str1=1).

ポイント
  • if [ 評価式 ] の部分は全てのコマンドをスペースで区切る必要がある.
  • スクリプトを途中で終了する場合にはexitを使う.
  • 評価演算子は評価する値の型によって記述方法が異なる(表1.6.x).

表1.6.1: 文字列評価式
str1 = str2文字列str1とstr2は一致する
str1 != str2文字列str1とstr2は一致しない
-z str文字列strは空(null)である
-n str文字列strは空(null)ではない


表1.6.2: 数値評価式
int1 -eq int2整数int1とint2は等しい(EQual: int1==int2)
int1 -ge int2整数int1はint2以上(Greater than or Equal: int1>=int2)
int1 -gt int2整数int1はint2より大きい(Greater Than: int1>int2)
int1 -le int2整数int1はint2以下(Less than or Equal: int1<=int2))
int1 -lt int2整数int1はint2より小さい(Less Than: int1<int2)
int1 -ne int2整数int1とint2は等しくない(Not Equal: int1 != int2)


表1.6.3: ファイル評価式
-d filefile はディレクトリである
-f filefile は通常ファイルである
-r filefile は読み出し可能である
-s filefile の長さは0バイトではない
-w filefile は書き込み可能である
-x filefile は実行可能である

Level3: 以下の機能を満たすシェルスクリプト (level3.sh) を作成せよ.
  • int型の引数を2個取り,それぞれ int1, int2 として設定(保存/代入)する.
  • 引数が2個以外の場合(0個,1個や,3個以上)には使い方を出力して終了する.
  • int1 と int2 を数値比較し,以下のように出力すること.
prompt> ./level3.sh

 Usage: prompt> ./level3.sh int1 int2

prompt> ./level3.sh 10 20

 int1=10, int2=20
 int1 is less than int2.

prompt> ./level3.sh 10 10

 int1=10, int2=10
 int1 is equal to int2.

prompt> ./level3.sh 20 10

 int1=20, int2=10
 int1 is greater than int2.


1.7. ループ制御(for, while)

for文による繰り返し処理の書き方は,C言語と比べると大きく異なります. 通常,シェルスクリプトにおける for 文は「リスト内の各要素に対して実行する繰り返し処理」に用います.

#!/bin/sh
# (例1.7.1) for文による繰り返し処理の例: example1.7.1.sh
list="1 2 3 4 5"
for value in $list
  do
  echo value=$value
done

# 実行例
sh-2.05b$ ./example1.7.1.sh 
value=1
value=2
value=3
value=4
value=5
sh-2.05b$

C言語の for に近い表現は while です.

#!/bin/sh
# (例1.7.2) while による繰り返し処理の例: example1.7.2.sh
a=0
while [ $a -lt 5 ]
  do
  echo "a=$a"
  a=`expr $a + 1`
done

# 実行例
sh-2.05b$ ./example1.7.2.sh 
a=0
a=1
a=2
a=3
a=4
sh-2.05b$
ポイント
  • for 文における「リスト」は半角スペースか改行で区切る必要がある.
  • 繰り返し処理はdo ... doneで囲う必要がある.
  • i++ のような記述が出来ないため,n回繰り返す処理を書きたい場合にはi=`expr $i + 1`のように自前で回数計算する必要がある.
Level4: 以下の機能を満たすシェルスクリプト (myls.sh) を作成せよ.
  • 指定したディレクトリの内容を表示するコマンド myls.sh を作成せよ.
  • 指定されたディレクトリが存在しない場合には「Not found: $dir」等のようにエラーを出力して終了する事.
  • 指定されたディレクトリ内に存在するディレクトリと通常のファイルは,出力を分けて表示すること.
  • ディレクトリの後ろには "/" を表示すること.
  • ヒント:ファイルの取得には "ls -1" を使っても良い(注:"l"(エル)では無く,数字の"1").逆に,-1 以外のオプションを使うのは NG です.
prompt> /bin/ls -FC ~/jikken1/shell/level4

a-file  dir1/  dir2/  file1  file2  y-dir/

prompt> ./myls.sh ~/jikken1/shell/level4

dir1/
dir2/
y-dir/
a-file
file1
file2

  • CheckPoint1: 任意のディレクトリに対して myls が実行可能である.
  • CheckPoint2: 引数がファイルや無効なディレクトリ・ファイル名である場合の処理が出来ているか?
  • Optional1: オプションを指定することでディレクトリのみファイルのみを変更できるようにする(getops, case を利用する)
  • Optional2: ディレクトリや実行ファイル等に色をつけてみる(配色は自由).

    ヒント:エスケープシーケンスを使う必要がある.

% echo ^[[33m test
 test
 *^[  は Ctrl+v, Esc で入力できる

Level5: 以下の機能を満たすシェルスクリプト (myupper.sh) を作成せよ.
  • 指定されたファイル名を小文字から大文字に変換するスクリプト myupper.sh を作成せよ.
  • ヒント:tr コマンド,ワイルドカードについて調べる.
prompt> ls
file1.txt  file2.tex  file3.dat  myupper.sh
prompt> ./myupper.sh file1.txt file2.tex
prompt> ls
FILE1.TXT  FILE2.TEX  file3.dat  myupper.sh
  • CheckPoint1: 指定されたファイル名*のみ*がちゃんと大文字に変換されるか?
  • CheckPoint2: 存在しないファイルの扱いは?
  • Option: 大文字→小文字?
Level6: 以下の機能を満たすシェルスクリプト (mymv.sh) を作成せよ.
  • 第1引数で指定された拡張子を持つファイルに対し,拡張子を第2引数に変換するスクリプト mymv.sh を作成せよ.
  • ヒント:basename コマンドについて調べる.
prompt> ls
file1.ps  file2.ps  file3.eps  mymv.sh
prompt> ./mymv.sh ps jpg
prompt> ls
file1.jpg file2.jpg file3.eps  mymv.sh
  • CheckPoint1: 指定したファイルの拡張子のみが変更されるか?
  • Option: Level5と6を1つのスクリプトにまとめ,オプション指定により機能を使い分けられるようにする.例えば,-u なら大文字化,-l なら小文字化,-e なら拡張し変更.(ヒント:getopts)

1.8. ヒア・ドキュメント

コマンドに,(改行コード込みの)複数行の文字列を標準入力させることが出来ます. これにより,インタラクティブなアプリケーション(シェルやgnuplotなど)に対して,複数のコマンドを実行させることが出来ます.

#!/bin/sh
# (例1.8) ヒア・ドキュメントの例: example1.8.sh
gnuplot <<ENDHOGE
set terminal png
set output "test.png"
set xlabel "Time"
set ylabel "Value"
set title "y=sin(x)"
plot sin(x)
ENDHOGE

# 実行例
prompt> ./example1.8.sh
prompt> ls
example1.8.sh  test.png
prompt> open test.png

ポイント
  • gnuplot 等への「入力スクリプト」そのものを作り出すスクリプトを作成することで,外部コマンドを利用した高機能なシェルスクリプトを作成できる.
  • 例えば,上記例での sin(x) を引数から代入させれば,標準関数の作図が1コマンドで実現できる(オプション課題: 任意の gnuplot スタイル数式をグラフ化するスクリプトを作成せよ).

1.9. gnuplot の利用

Level7: gnuplot をスクリプトファイルを通して利用せよ

gnuplot 入門を参考に,数値データをプロットする gnulot スクリプトを作成せよ. どのような数値データでも構わないが,以下の条件を満足するものとする.

  • 条件0: gnuplot へのコマンド受け渡しをスクリプトファイルとする事.

    具体的には,gnuplot コマンドを列挙したファイル command.plot を作成し,コマンドライン上から以下のように実行するか,1.8節の「ヒア・ドキュメント」形式を利用する事.

    prompt> gnuplot < command.plot
    

  • 条件1: 数値データ数を10件以上とする事.
  • 条件2: LaTeX の出力に含めるために,gnuplot の出力画像形式を EPS 形式とする事.
  • 条件3: 軸の説明やグラフのタイトルを図内に含める事.
  • その他参考: Level9 のサンプルスクリプト(sample-script.tgz)

    sample-script/log/{log_anaysis1_comment.sh,sample.dat}

    注意点として,level9 での gnuplot コマンド例では PNG 形式での出力となっている.EPS 形式で出力するには以下のようにすること.

    # Level9 の gnuplot スクリプト例
    set terminal postscript eps color
    set output "daily.eps"
    set title "Daily access log"
    set xlabel "Date (2004)"
    set ylabel "Access rate"
    plot "sample.dat" using 2:1 with boxes
    

1.10. ワイルドカード

パターンを記述するにはワイルドカードを使います.

#!/bin/sh
# (例1.10) ワイルドカードの例: example1.10.sh
if [ $# -eq 1 ] ; then
  str1="$1"
else
  echo "Usage: prompt> $0 arg1"
  exit 1
fi

case $str1 in
  [a-z])
    echo "str1 is a single small word: $str1"
    ;;
  [A-Z])
    echo "str1 is a single large word: $str1"
    ;;
  ?)
    echo "str1 is a single word except for alphabet: $str1"
    ;;
  *)
    echo "str1 is a string: $str1"
    exit 1
esac

# 実行例
sh-2.05b$ ./example1.10.sh hoge
str1 is a string: hoge
sh-2.05b$ ./example1.10.sh h   
str1 is a single small word: h
sh-2.05b$ ./example1.10.sh H
str1 is a single large word: H
sh-2.05b$
ポイント
  • [abc]は,「aまたはbまたはcのいずれか」にマッチする.
  • [a-c]も上記と同じ意味になる.
  • ?は任意の1文字にマッチする.

1.11. 関数の定義と使用

再利用しやすくするため,良く利用するコマンド群をまとめて一つの関数として設定することが出来ます.

#!/bin/sh
# (例1.11) 関数定義の例: example1.11.sh
function1() {
    echo "--> This is function1."
    echo "The number of args: $#"
    echo "The argument list: $*"
    index=1
    for arg in $*
    do
      echo "The ${index}st argument: $arg"
      index=`expr $index + 1`
    done
}

function1 a b c
echo "----------"
function1 hoge


# 実行例
sh-2.05b$ ./example1.11.sh
--> This is function1.
The number of args: 3
The argument list: a b c
The 1st argument: a
The 2st argument: b
The 3st argument: c
----------
--> This is function1.
The number of args: 1
The argument list: hoge
The 1st argument: hoge
sh-2.05b$ 





2. シェルスクリプトサンプル(オプション課題例)

2章はオプション課題の例です. それ以外の独自の課題を設定し,取り組んでもらっても構いません. また,必ずしもシェルスクリプトで取り組む必要もなく,他のスクリプト言語を利用しても構いません.



[ サンプル ] sample-script.tgz

ダウンロード後,自動解凍されない場合は以下のようにして解凍してください. また,各ファイルの説明は「0Readme.txt」を参照してください.

> tar xvfz sample-script.tgz
(または)
> tar xvf sample-script.tar

2.1 引数の使い方: up2html.sh,デーモン起動スクリプト

  • サンプル内の up2html.sh は,引数を利用して異なる処理を実行するシェルスクリプトの例である.(動作確認用スクリプトなので,echo で実行内容を出力させている)
  • [ 参考 ] いくつか less で覗いてみよう!
    • (Linux系OS)デーモン起動時にも case を用いたスクリプトを利用しており,Linux系OS(e.g., pw/nirai/kanai/naha) では /etc/rc.d/init.d/ にある.
    • (Mac OS X)

2.2 サムネイル生成

  • thumbnail1.sh: SUFFIX で指定した拡張子を持つ画像ファイルをリストアップ.
  • thumbnail2.sh: SUFFIX で指定した拡張子を持つ画像ファイルを表示するHTMLファイルを生成.
  • thumbnail3.sh: SUFFIX で指定した拡張子を持つ画像ファイルの縮小画像を生成し,表示するHTMLファイルを生成.
Level8(オプション)
thumbnail3.sh をベースに,1ページ内に納める写真数(photo_num)を指定し,自動的にページ分割するように拡張せよ.(下表参考)

photo_numpagename (photos)
photo_num=1
  • page1.html (photo1)
  • page2.html (photo2)
  • page3.html (photo3)
  • page4.html (photo4)
  • page5.html (photo5)
photo_num=2
  • page1.html (photo1, 2)
  • page2.html (photo3, 4)
  • page3.html (photo5)
photo_num=3
  • page1.html (photo1, 2, 3)
  • page2.html (photo4, 5)


2.3 ログ解析

解析ファイル:ダウンロードした sample-script 内にある log/access_log を利用せよ.

httpd へのアクセスログは(一般的には) /var/log/httpd/ にあり,最新は access_log である.

access_log には「アクセス先IP,時刻,メソッド,リクエストのステータスコード」等が含まれている(参考:Apache 1.3 ドキュメント).

このアクセスログを下記の要領で解析するためのシェルスクリプトを作成せよ.

Level 9.1(オプション)
access_log に記載されているアクセス総数をカウントせよ.

[Tips] man wc

Level 9.2(オプション)
日毎のアクセス数,IP毎のアクセス数をカウントせよ.

[Tips] man grep, man uniq

Level 9.3(オプション)
Level 9.2 で求めたカウント数を棒グラフ作成せよ(何れか一つを必須とし,残りはオプションとする).
  • 日毎アクセス数:横軸日付,縦軸アクセス数
  • IP毎アクセス数:横軸IP,縦軸アクセス数(アクセス数トップ10のみで良い)

[Tips] man cut, man tr, man uniq, man sort
[Tips] gnuplot による自動グラフ生成:log/log_anaysis1_comment.sh

# ファイル「sample.dat」に日毎アクセス数を記載してある場合
echo 'set terminal png' > daily.gnuplot
echo 'set output "daily.png"' >> daily.gnuplot
echo 'set title "Daily access log"' >> daily.gnuplot
echo 'set xlabel "Date (2004)"' >> daily.gnuplot
echo 'set ylabel "Access rate"' >> daily.gnuplot
echo 'plot "sample.dat" using 2:1 with boxes' >> daily.gnuplot

gnuplot < daily.gnuplot

Level 9.4(オプション)
日毎アクセス数の中で最もアクセ数の多かった日について,時間あたりのアクセス数推移図を作成せよ.
Level 9.5(オプション)
Level 9.1-9.4 について,結果をHTMLファイルとして出力せよ.
Check points, options
  • 任意のファイル名について実行出来るか?
  • 任意の日付について実行出来るか?
  • pw にてリアルタイムで解析するにはどうすれば良いか?
  • pw にてバッチ処理(一日毎に解析など)するにはどうすれば良いか?

2.4 世界のナベアツ問題

  • 「3の倍数と3の付く数字だけアホになり、5の倍数だけ犬っぽくなります」(参考:渡辺鐘(Wikipedia))をスクリプトで実現.
  • 文字のみでの出力でも良いですが,音声出力にもトライしてみよう.
  • ヒント:Mac OS X なら,Speech Manager(Text-to-Speech)の音声合成機能を say コマンドで簡単に音声出力できます(man say).
  • 関連話題: FizzBuzz問題

2.5 カウンターの作成

  • 実行する度にスクリプトで数を数えて行くスクリプト(カウンターCGIのコマンドライン版)を作成せよ.
  • ヒント:数えた結果を覚えておく必要があるが,ファイルに保存する方法で構いません.

#動作イメージ
sh-2.05b$ ./counter.sh
1
sh-2.05b$ ./counter.sh
2
sh-2.05b$ ./counter.sh
3



参考文献・サイト

sh(bash)スクリプト
gnuplot関連
ImageMagick関連
その他