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






更新情報







実験の進め方

内容と達成目標

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

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

コメント

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

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

進め方
  • テキスト・補助教材:本ページや参考文献参照(サンプルソースもあります)
  • 作業スタイル:個人作業(1人1レポート)
課題と提出方法
  • 1人1レポート提出。
  • レポートへの取り組み方は2通りあります。どちらの方で取り組むかは各自で判断してください。
    • 一つ目は、Level1からLevel7まで全てについて取り組むこと。オプション課題をしない場合はこちらになります。
    • 二つ目は、独自設定課題を含めたオプション課題に取り組むこと。この場合は、Level1-3は完全に省略して構いません。Level4-6はどれか一つ選択してやってください。Level7は必ずやって下さい。(注意:オプション課題をやっていないにもかかわらず勝手に省略した場合には大幅減点となります)
  • 前述したいずれかの取り組み方で課題をやり、レポートとしてまとめよ。Level毎に以下の項目を報告書としてまとめること。ただし、全てを個別に報告する必要はなく、例えば「実験結果と考察」という節を設けても構わない。
    • 課題説明
    • 作成したスクリプト本体の解説
    • 実験結果
    • 考察
  • 2章は解説のみで課題はありません。3章は全てオプション課題であり、独自に設定した自主課題も含めてやるやらないは任意である。
  • レポートの1枚目には以下の項目を記述すること。
    • 実験テーマ名、担当教員名
    • 氏名、学籍番号
    • 実験日、提出期限日、提出した日
    • オプション課題に取り組んだ場合には、課題毎にLevelX-1、LevelX-2、、のようにインデックスを付け、そのインデックスを1枚目にも明記すること。
  • 提出物
    • [提出物1] レポートは LaTeX で作成し、PDFファイルとして作成する事。提出物には LaTeX ファイル一式(tex, eps ファイル等全て)を含む事。ファイル名の例:e0957xx.pdf
    • [提出物2] 作成したスクリプト一式
  • 上記2点を naha にアップロードし、tnal@ie.u-ryukyu.ac.jp 宛に以下のタイトルで報告メールを送信する事。報告メールが無い場合には減点となります(ホウレンソウ)

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


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

    % cd   (ホームディレクトリに移動)
    % rsync  -auve  ssh \
       ~/jikken1/shell/ \
       e0957xx@naha:/home/teacher/tnal/jikken1-tue/e0957xx/
    % rsync  -auve  ssh \
       ~/jikken1/shell/ \
       e0957xx@naha:/home/teacher/tnal/jikken1-fri/e0957xx/
    
  • 提出期限:実験日の7日後まで(5/11のクラスの期限は5/18、5/14のクラスは5/21)。
評価基準
  • レポートでは指定した課題をこなしている(提出している)事を前提に基準点を設け、以下の項目に沿って加点・減点を行う。オプション課題をやらない場合の基準点は60-70点程度、オプション課題をやる場合の基準点は70-80点程度である。特に、テーマに関連する事柄を自主的にやってきた場合には積極的に加点対象対称として採点するので、各自創意工夫して自主課題に取り組む事。
  • 採点後、優秀なレポートを期間限定で公表します。

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



0. 事前準備

自分のノートPC(Mac OS X)を利用する場合は1を、 PCクラスタ(cls, pw)等のLinuxを利用する場合は2を準備してください。

なおPCクラスタを利用する際には、PCクラスタのアップデートが2010/5/5に予定されていましたので、何かしら不具合が起きた場合にはサーバ班や私宛てに相談してください。

  1. Mac OS X 側の準備
    1. Xcodeをインストール。

      OSを再インストール等していなければ、インストール大会でインストール済みです。インストールされていれば、/Developer/Applications/Xcode.app があります。無ければ先程のリンク先を参照してインストールしてください。

    2. EasyPackageのmath/gnuplot, graphics/ImageMagickをインストール。

      EasyPackage.app がインストールされていない学生は、インストール大会を参照の上インストールしてください。

    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. 各種アプリの動作確認。
      • gnuplot参考:gnuplot入門(今回は数値データをプロットし、印刷(画像ファイルとして保存)できればOK)
      • ImageMagick参考:Imagemaagickの使い方(今回はconvertが使えればOK)

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


1. shell script の基礎

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

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



1.0. 諸注意

スクリプトプログラミングに限った話ではありませんが、ファイルやディレクトリを(上書き)作成・編集・削除といった処理の自動化を行いますので、誤ってファイル等を削除してしまう可能性があります。スクリプトを実行する際には十分に気をつけること。

基本的にはバックアップを取りながら作業をすることが望ましいですが、それ以外にも以下のような対策が考えられます。

  • echo(C言語のprintf()相当)でコマンド列や引数を出力させて確認し、出力結果が想定した通りであれば echo を削除して実行する。
  • rm や mv コマンドを実行する際には -i オプションを付けて確認し、動作が想定した通りであればそれらを削除する。
  • 仮想OS環境を構築し、そこでやる。



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-3.2$      # <--プロンプトが変わっているのを確認
sh-3.2$ 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=8, b=2 とし、四則演算を計算する。
  • 実行結果は以下のように出力すること。
    prompt> ./level1.sh
    
    # Level1の実行結果
    a=8, b=2
    a+b=10
    a-b=6
    a*b=16
    a/b=4
    
    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: 軸の説明やグラフのタイトルを図内に含める事。
  • その他参考:

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

    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章はシェル上で利用出来る便利なコマンドをいくつか紹介します。 詳細な説明は man コマンドで調べる事。関連のあるコマンド等が「SEE ALSO」蘭に列挙されていますので、一通り読むだけでも勉強になります!

wc
  • 説明: word, line, character, and byte count
  • 使用例
    prompt> wc file.txt
    
grep
  • 説明: print lines matching a pattern
  • 使用例(Webサーバのエラーログ中に「error」と記述されている行のみを抽出)
    prompt> grep error /var/log/httpd/error_log
    
cut
  • 説明: select portions of each line of a file
  • 使用例(半角スペースを区切り文字としてみなした時の、8番目の要素を抽出)
    prompt> grep error /var/log/httpd/error_log | cut -f8 -d" "
    
tr
  • 説明: translate characters
  • 使用例(IPアドレスの後ろに付いている]を削除)
    prompt> grep error /var/log/httpd/error_log | cut -f8 -d" " | tr -d "]"
    
sort
  • 説明: sort lines of text files
  • 使用例(数値でソート)
    prompt> grep error /var/log/httpd/error_log | cut -f8 -d" " | tr -d "]" | sort -n
    
uniq
  • 説明: report or filter out repeated lines in a file
  • 使用例(IPアドレス毎の個数をカウント)
    prompt> grep error /var/log/httpd/error_log | cut -f8 -d" " | tr -d "]" | sort -n | uniq -c
    
sleep
  • 説明: suspend execution for an interval of time
  • 使用例
    prompt> sleep 1
    
head
  • 説明: display first lines of a file
  • 使用例
    prompt> head /var/log/httpd/error_log
    
tail
  • 説明: display the last part of a file
  • 使用例
    prompt> tail /var/log/httpd/error_log
    
man
  • 説明: format and display the on-line manual pages
  • 使用例
    prompt> man man
    





3. オプション課題例

ここで示している課題は全て「オプション課題の例」です。 同じ課題に取り組んでも構いませんし、アレンジしても構いませんし、オリジナル課題を設定するのもOKです。 自由に調理してください!


3.1 ゴミ箱の作成

通常 rm/rmdir でファイルやディレクトリを削除すると、その時点で誤って削除したファイル等を復旧する事はできない。これを Windows や Mac OS X にあるような「ゴミ箱」のように機能するコマンドを作成せよ。

  • ヒント:「ゴミ箱」に相当するディレクトリを作成し、スクリプト実行時に引数で指定されたファイル等をそのディレクトリに移動する。
  • 拡張例:「ゴミ箱を空にする」に相当する機能をどう実現する?
  • 拡張例:同じファイル・ディレクトリ名が既に退避されている場合はどうする?
  • 拡張例:退避させたファイル等を元のディレクトリに戻すにはどうする?
  • 注意:スクリプトの記述を誤り、想定外のファイルやディレクトリを削除してしまうことがあります!動作確認は注意して行ってください!!

3.2 バックアップスクリプトの作成

任意の指定されたディレクトリ(ホームディレクトリであったり、講義毎に用意してあるディレクトリだったり)のバックアップorスナップショットを作成するスクリプトを作成せよ。

  • ヒント:tar, gz, rsync, rsnapshot コマンドについて調べる。
  • 拡張例:dateコマンドを用いて「バックアップ時の日付」をスナップショット名に含める事で「いつのスナップショットか」が分かりやすくなるようにする。
  • 拡張例:指定したディレクトリのスナップショットが既にある場合、現在のディレクトリを一時的に退避(最新版としてスナップショットを作成でも可)させ、スナップショットから当時のディレクトリを復元できるようにする。
  • 拡張例:「一週間毎にバックアップを取る」等、一定の時間毎にスクリプトを実行できるようにする。

3.3 ファイルの漢字コードや改行コードを変換するスクリプトの作成

nkfコマンドを使ってファイルの漢字コードや改行コードを変更する事が可能である。しかし、オプションを覚えたり、一時的に別ファイルを作成する必要があったりしてやや不便な点もあるので、より便利なスクリプトを作る。

  • ヒント:nkfコマンドについて調べる
  • 拡張例:自分が使いやすいオプション指定ができるようにする。
  • 拡張例:指定されたファイルの文字コードや改行コードを変換した内容で、元のファイルに書き出す。

3.4 スケルトン生成用スクリプトの作成

LaTeXにしろHTMLにしろ、共通したヘッダ情報やお約束を含める必要がある。新規作成する時点である程度ほ骨組みを含めたファイル(スケルトン)を生成する。

  • ヒント:ヒア・ドキュメント
  • 拡張例:スケルトンを生成したいファイルを決め、変数になりうる部分を抽出し、コマンドラインから指定出来るようにする。
  • 関連:Rails等の web application 作成用フレームワークでも同様の機能が多々利用されている。それらについて調べてみる。

3.5 ping 確認用スクリプトの作成

(例えば)PCクラスタ180台に対して ping 接続を確認したい。指定されたIPアドレスのリストや、指定されたアドレス領域に対して ping を実行し、結果を出力する。

  • ヒント:複数のIPアドレスを指定させるには、予めファイルに「1行=1IPアドレス」のように記述させる事でも可能だし、「192.168.0.1 180」のように、連続したIPアドレスであれば起点と終点を指定する事で範囲を入力させる事が可能。
  • 機能例:IP毎の結果だけでなく、集計結果も出力出来るようにする。
  • 機能例:SMTPやHTTPが可能かについてもチェック出来るようにする。
  • 機能例:直接コンソール上に出力する形式だけでなく、HTML出力する等してみやすい詳細結果を出力出来るようにする。

3.6 デーモン起動スクリプトを読んでみる

多くのLinux系OSにおいて、デーモン(サービス)を起動するためのスクリプトが

/etc/init.d/
以下に用意されている。 それらのスクリプトでは、オプション指定時に start/stop/restart 等を指定する事でデーモンを起動/停止/再起動することができるようになっている事が多い。 勉強のためにいくつかそれらのスクリプトを読んで解説してみる。

  • 例えば Web サーバ は /etc/init.d/httpd というスクリプトで起動/停止が可能である。





4. レポート骨組み

LaTeXの使い方がまだ良くわかっていない学生のために、レポートの骨組みを用意しました。

  • ダウンロード: reportskel.tgz
  • 骨組みをコンパイルして生成出来るPDFファイル: info1-script.pdf
  • コンパイル方法
    prompt> platex info1-script.tex
    prompt> platex info1-script.tex
    prompt> dvipdfmx info1-script.dvi
    


参考文献・サイト

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