(2014年度) 情報工学実験1 : スクリプトプログラミング（當間）

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

目次

更新情報
進め方

- 内容と達成目標
実験の進め方
課題と提出方法
評価基準
- コンテンツ
- 0. 事前準備
1. shell script の基礎

- 1.0. 諸注意
1.1. bash シェルの実行
1.2. シェル変数への値の代入と参照
1.3. 特殊文字の利用（エスケープシーケンス）
1.4. シェルスクリプトの作成と実行
1.5. 特殊な変数
1.6. 条件分岐（if, case, []）
1.7. ループ制御（for, while）
1.8. ヒア・ドキュメント
1.9. 正規表現
1.10. sedによるテキスト処理
1.11. gnuplotによるグラフ描画
1.12. dotによるグラフ描画
- 2. 便利なコマンド (紹介)
- wc, grep, cut, tr, sort, uniq, sleep, head, tail, man
- 3. 課題
- Level 1: ツイートリストから「ツイート数/日」をカウントしてみよう。
Level 2: ツイートリストから mention map を作成してみよう。
- 4. レポート骨組み
X. オプション課題例
- (X.1 ゴミ箱の作成)
X.2 バックアップスクリプトの作成
X.3 ファイルの漢字コードや改行コードを変換するスクリプトの作成
X.4 スケルトン生成用スクリプトの作成
X.5 ping 確認用スクリプトの作成
X.6 デーモン起動スクリプトを読んでみる
X.7 サンプルスクリプトを読んでみる
X.8 Easy Package 本体スクリプトを読んでみる

参考文献・サイト

更新情報

[2014-05-28] 昨年度の資料、参考文献/サイトを参考に、コンテンツ検討中。
[2014-05-31] 課題検討中。
[2014-06-01] 仮アップ。課題調整中。
[2014-06-03] Level 2 修正（手順2を追加）。
[2014-06-09] ツイートリストについてほ補足追加。提出時の補足追加。

## 実験の進め方

内容と達成目標

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

（達成目標0：LaTeXの環境やコマンドを適切に利用してレポートを作成できる。）
達成目標1：シェル（sh/bash）スクリプトを読め、動作を理解する。
達成目標2：シェル上での正規表現を理解する。
達成目標3：シェルで繰り返し作業を使う。
達成目標4：（シェルで簡単なログ解析をスクリプトで組み）、その結果を gnuplot 等でグラフ作成する。

#### コメント

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

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

実験1,2のレポートは、基本的には1週間でレポートを仕上げ続ける形になるため、貯めることなく毎週仕上げるようにしよう。今回の実験では作成日を含めての1週間になるが、途中でタイムオーバーになることが想定できるならば「できる範囲」で期限内に仕上げ、努力したことが読み取れるように報告書を作成してください。特に、独自課題に関しては完成までしなくても（途中であっても）構わないので、取り組んだことが分かるように報告書に記述すること（報告書に記述の無いことは評価できません）。

進め方

テキスト・補助教材：本ページや参考文献参照（サンプルソースもあります）
作業スタイル：個人作業（1人1レポート）

課題と提出方法

1人1レポート提出。
レポートへの取り組み方は3通りあります。どちらの方で取り組むかは各自で判断してください。火曜日クラスでの当日進展具合で最終決定します。

- 一つ目は、全ての課題（Level1, Level2）について取り組むこと。オプション課題をしない場合はこちらになります。
二つ目は、独自設定課題を含めたオプション課題(1つ以上)に取り組むこと。この場合は、Level1は省略して構いません。Level2は必ずやって下さい。（注意：オプション課題をやっていないにもかかわらず勝手に省略した場合には大幅減点となります）
(三つ目は、当日進展が遅い場合を想定し、この場合にはLevel2だけ（オプション無し）で構いません。)
- 前述したいずれかの取り組み方で課題をやり、レポートとしてまとめよ。Level毎に以下の項目を報告書としてまとめること。ただし、全てを個別に報告する必要はなく、例えば「実験結果と考察」という節を設けても構わない。
- 課題説明
作成したスクリプト本体の解説
実験結果
考察
- レポートの1枚目には以下の項目を記述すること。
- 実験テーマ名、担当教員名
氏名、学籍番号
実験日、提出期限日、提出した日
オプション課題に取り組んだ場合には、課題毎にLevelX-1、LevelX-2、、のようにインデックスを付け、そのインデックスを1枚目にも明記すること（1枚目を見ただけでオプション課題をやったかどうかが分かるように書くこと）。
- 提出物
- [提出物1] レポートは LaTeX で作成し、PDFファイルとして作成する事。提出物には LaTeX ファイル一式（tex, 図ファイル等全て）を含む事。ファイル名の例：e1357xx.pdf
[提出物2] 作成したスクリプト一式
- 上記2点を repo サーバにアップロードし、tnal@ie.u-ryukyu.ac.jp 宛に以下のタイトルで報告メールを送信する事。報告メールが無い場合には減点となります（ホウレンソウ）

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

- （アップロード例）
以下は ~/jikken1/shell/ に提出物を保存している場合の例です。
修正する場合も同じコマンドで構いませんが、アカウント名（e1357xx）を間違えないように注意する事！
rsync 自体の説明は例えばここを参照してください。
- 注意点1: 両方（送信元＆送信先）ともディレクトリ名の後ろにスラッシュを付けるのを忘れずに！
- 注意点2: ツイートリストは不要です。アップロードしないでください。

% cd (ホームディレクトリに移動)
% rsync -auve ssh ~/jikken1/shell/ e1357xx@repo:/home/teacher/tnal/jikken1-tue/e1357xx/
% rsync -auve ssh ~/jikken1/shell/ e1357xx@repo:/home/teacher/tnal/jikken1-fri/e1357xx/
# 注意：
# ・スラッシュの有無で引数の意味が大きく異なります。

提出期限：実験日の7日後まで（6/3のクラスの期限は6/10、6/6のクラスは6/13）。

評価基準

レポートでは指定した課題をこなしている（提出している）事を前提に基準点を設け、以下の項目に沿って加点・減点を行う。オプション課題をやらない場合の基準点は60-70点程度、オプション課題をやる場合の基準点は70-80点程度である。特に、テーマに関連する事柄を自主的にやってきた場合には積極的に加点対象対称として採点するので、各自創意工夫して自主課題に取り組む事。
採点後、優秀なレポートを期間限定で公表します。

加点

独自に行った関連課題に関する報告（積極性）。
実験中に示した手法ではなく、自力で探し出した異なる手法で問題を解決した場合（積極性・実践性・創造性）。
手法の利点・欠点や限界等に関して自主的にトライした結果・考察が示されている場合（積極性・専門性）。
レポートの見せ方に関する工夫など（コミュニケーション能力）。
その他、本テーマに関連する実験的側面上「積極性・実践性・創造性・コミュニケーション能力」等の観点から評価できるもの。

減点

先行研究や事例、レポート、web等を参照しているにも関わらず、それらを参考文献として参照していない場合（一般倫理）。
論理的矛盾が見られる場合（論理性）。
結果を示さずに考察のみを記載してたり、結果に対する考察に整合性が見られない場合（コミュニケーション能力）。
タイプミスや可読性の欠如、数式等記号の印字ミス、提出期限の遅れ等、多方面に関して大きな誤りではない場合。

## 0. 事前準備

自分のノートPC（Mac OS X）を利用する場合は1を、
FedoraやCentOSといったLinux系OSを利用する場合は2を準備してください。

Mac OS X での準備

Xcodeをインストール。

- OSを再インストール等していなければ、インストール大会でインストール済みです。インストールされていれば、/Developer/Applications/Xcode.app があります。無ければ先程のリンク先を参照してインストールしてください。
- EasyPackageのmath/gnuplot, graphics/ImageMagick, devel/libtoolをインストール。（gnuplotとconvertコマンドが動くようならOK）
- EasyPackage.app がインストールされていない学生は、インストール大会を参照の上インストールしてください。
- Graphvizをインストール。サイトが重くて開けないようなら実験中だけこちらからダウンロードできます。
各種アプリの動作確認。

- gnuplot参考：gnuplot入門（今回は数値データをプロットし、印刷(画像ファイルとして保存)できればOK）
ImageMagick参考:Imagemagickの使い方（今回はconvertが使えればOK）
Graphviz参考: Graphvizによる有向グラフの自動生成（今回はdotが使えればOK）
- Linuxでの準備

gnuplot をインストール（参考：yumとは？）。

- MacBook-X11# ssh -X cls001　　　　#クラスタにログイン
cls001# which gnuplot　　　　　　#gnuplotがインストールされているかを確認
cls001# sudo yum install gnuplot　#yum でパッケージインストール
- ImageMagick をインストール。やり方は上記参照。
各種アプリの動作確認。

gnuplot参考：gnuplot入門（今回は数値データをプロットし、印刷(画像ファイルとして保存)できればOK）
ImageMagick参考:Imagemaagickの使い方（今回はconvertが使えればOK）
Graphviz参考: Graphvizによる有向グラフの自動生成（今回はdotが使えればOK）

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

## 1. shell script の基礎

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

日頃良く使う一連のコマンド群をより簡単に実行したい。
ファイルやディレクトリを手軽に扱いたい。
複数のファイル/ディレクトリに対して同一の処理を実行したい。
自動化したい。定期的に実行したい。

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

### 1.0. 諸注意

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

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

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

### 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

演習課題1: 以下の機能を満たすシェルスクリプト (exl1.sh) を作成せよ。

a=8, b=2 とし、四則演算を計算する。
実行結果は以下のように出力すること。

prompt> ./ex1.sh
# 演習課題1の実行結果
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番目の引数
$# スクリプトに渡された引数の個数
$* スクリプトに渡された全引数のリスト
$? 直前に実行したコマンドの終了ステータス

表1.5.2: 終了ステータス

0 コマンドが正常終了
1以上の任意の値 リダイレクトや展開に失敗して終了
1～125 コマンドが異常終了
126 コマンドは存在しているが、実行可能な状態ではない
127 コマンドが存在していない
129～255 シグナルを受信したためにコマンドが強制終了された

#!/bin/sh
# (例1.5) 特殊変数の利用例: example1.5.sh
echo "引数の数 : $#"
echo "スクリプト名 : $0"
echo "第1引数 : $1"
echo "第2引数 : $2"
echo "引数一覧 : $*"
echo "プロセスID : $$"
# 実行例
sh-2.05b$ ./example1.5.sh 1 2 3 4
引数の数 : 4
スクリプト名 : ./example1.5.sh
第1引数 : 1
第2引数 : 2
引数一覧 : 1 2 3 4
プロセスID : 2548
sh-2.05b$

# (例1.5.2) 終了ステータスの確認
prompt> ls
prompt> echo $? #正常終了時の値を確認
prompt> ls hogege
prompt> echo $? #異常終了時の値を確認

演習課題2: 以下の機能を満たすシェルスクリプト (ex2.sh) を作成せよ。

ex1.sh を拡張（複製して新しくファイルを作成）する。
ex1.sh では演算対象の a,b をスクリプト内で設定していたが、この2つの値を実行時の引数から設定するようにする。
実行結果は以下のように出力すること。以下では2例示しているが、重要なのは変数 a,b をスクリプトへの引数として実行時に指定できるようにする事である。

prompt> ./ex2.sh 8 2
# 参考出力結果(ex2)
a=8, b=2
a+b=10
a-b=6
a*b=16
a/b=4
prompt> ./ex2.sh 10 5
# 参考出力結果(ex2)
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 file file はディレクトリである
-f file file は通常ファイルである
-r file file は読み出し可能である
-s file file の長さは0バイトではない
-w file file は書き込み可能である
-x file file は実行可能である

演習課題3: 以下の機能を満たすシェルスクリプト (ex3.sh) を作成せよ。

int型の引数を2個取り、それぞれ int1, int2 として設定(保存/代入)する。
引数が2個以外の場合（0個、1個や、3個以上）には使い方を出力して終了する。
int1 と int2 を数値比較し、以下のように出力すること。

prompt> ./ex3.sh
Usage: prompt> ./ex3.sh int1 int2
prompt> ./ex3.sh 10 20
int1=10, int2=20
int1 is less than int2.
prompt> ./ex3.sh 10 10
int1=10, int2=10
int1 is equal to int2.
prompt> ./ex3.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`のように自前で回数計算する必要がある。

### 1.8. ヒア・ドキュメント

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

#!/bin/sh
# (例1.8) ヒア・ドキュメントの例: example1.8.sh
gnuplot <<ENDHOGE
set terminal svg
set output "test.svg"
set xlabel "Time"
set ylabel "Value"
set title "y=sin(x)"
plot sin(x)
ENDHOGE
#上記はSVG形式での出力例。
#EPS形式で出力したいなら "set terminal postscrit eps" 等とする。
#gnuplotの実装によっては最初からpdf出力できるものも。
#詳細は"help terminal"でヘルプで確認しよう。
# 実行例
prompt> ./example1.8.sh
prompt> ls
example1.8.sh test.svg
prompt> open test.svg

ポイント

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

### 1.9. 正規表現

パターンを記述するには正規表現を使います。代表的な正規表現とその例を以下に示します。下記以外にもいろいろありますので、パターンマッチングする際に勉強してみよう。

記号 意味
. 改行文字以外の任意の1文字に一致。
* 「直前の1文字(or正規表現)」の0回以上の繰り返しに一致。例えば、メールアドレスのように @ の前に必ずアカウント名が来るなら「.*@」と書ける。
\+ 「直前の1文字」の1回以上の繰り返しに一致。
^ 行の先頭に一致。例えば ^a と書くと「aから始まるパターン」を表現。
$ 行の末尾に一致。例えば a$ と書くと「aで終わるパターン」を表現。
[] 括弧内の任意の1文字に一致。例えば [abc] なら「a or b or c を含むパターン」を表現。[0-9], [m-y], [A-D] のように範囲を指定することも可能。
| 前後のパターンいずれかに一致。例えば「[0-9]|[a-z]」なら「0～9か、もしくはa～zのいずれかに一致するパターン」を表現。
\t or [[:space:]] タブに一致。[:space:]はタブとスペースに一致。\tが効かない実装もあるので注意。

### 1.10. sedによるテキスト処理（エディタ）

参考: ドットインストールをまとめる(sed入門）

特定パターンに合致する部分を抽出・フィルタリング・編集することが可能。「パターン」はテキストそのもので書いたり、前述の正規表現を用いることができる。

例1: 学籍番号数字6文字(135700)をメールアドレス(e1357xx@ie.u-ryukyu.ac.jp)に変換する。

prompt> echo "135701\n135702" | sed -e "s/.*/e&/g"
e135701
e135702

-e: 正規表現を使うというオプション指定。
"s/1/2/g": 「1」が現れる度、「2」に置き換えるという置換指定。
.*: 正規表現（＝全て）
&: マッチしたテキスト全て。ここでは .* を指定していたため、全てのテキストが & に保存されている。

例2: 必要な箇所だけを抽出し、フォーマットを変更して出力する。

prompt> date
2014年 5月30日 金曜日 15時39分57秒 JST
prompt> date | sed -e "s/\([0-9]*\)年.*/\1/g"
2014
prompt> date | sed -e "s/\([0-9]*\)年 \([0-9]*\)月\([0-9]*\)日.*/\2-\3-\1/g"
5-30-2014

s/\(pattern1\)\(pattern2\)/\1/g: \(と\)でパターンの始まりと終わりを指定。左の例ではpattern1とpattern2の二つがある。マッチしたpattern1を使いたいなら、\1として参照できる。pattern2は\2として参照できる。

### 1.11. gnuplotによるグラフ描画

Gnuplotは2次元／3次元座標を用いたグラフ生成ツールとして使用されている。

例: シンプルな線グラフの例。

1行に「その日のツイート数」をline.dataとしてデータを保存しており、その推移を折れ線グラフで描画したいならば、以下のように実行する。

prompt> gnuplot
gnuplot> set terminal postscript eps
gnuplot> set output "line.eps"
gnuplot> set xlabel "Day"
gnuplot> set ylabel "Number of tweets"
gnuplot> set yrange [0:100]
gnuplot> plot "line.data" with line
prompt> open line.eps

上記では gnuplot を起動した上で一行ずつコマンド入力する例だが、これらのコマンドをファイルに保存しておき「gnuplot < command-flie」として実行することも可能（シェルのリダイレクト機能）。
グラフ生成する時は、原則としてベクター形式で作図し、texに埋め込むこと。
参考: gnuplot入門

### 1.12. dotによるグラフ描画

Graphvizに含まれるdotコマンドはグラフ自動生成コマンドとして様々なところで利用されている。例えばプログラミングのドキュメンテーション・ツールであるDoxygenファイルやクラス毎の警鐘関係等を可視化するために使用している。

例: シンプルなグラフの例。

graph.dotという形式でファイルを用意し、以下のように実行するだけ。

- prompt> dot -Tpdf graph.dot -o graph.pdf
prompt> open graph.pdf
- 参考

Graphvizの配色と矢印の太さと色サンプル
データのビジュアル化を最小の労力で

## 2. 便利なコマンド

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

wc

説明: word, line, character, and byte count
サンプルファイル: error_log
使用例

- prompt> wc error_log
- grep

説明: print lines matching a pattern
使用例（Webサーバのエラーログ中に「error」と記述されている行のみを抽出）

prompt> grep error error_log

unmatch (マッチしなかった行を抽出) するにはオプション -v を付けて実行。上の例だと「grep -v error error_log」と実行すると、errorを含まない行のみを抽出できる。

cut

説明: select portions of each line of a file
使用例（半角スペースを区切り文字としてみなした時の、8番目の要素を抽出）

- prompt> grep error error_log | cut -f8 -d" "
- tr

説明: translate characters
使用例（IPアドレスの後ろに付いている]を削除）

- prompt> grep error error_log | cut -f8 -d" " | tr -d "]"
- sort

説明: sort lines of text files
使用例（数値でソート）

- prompt> grep error error_log | cut -f8 -d" " | tr -d "]" | sort -n
- uniq

説明: report or filter out repeated lines in a file
使用例（IPアドレス毎の個数をカウント）

- prompt> grep error 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 error_log
- tail

説明: display the last part of a file
使用例

- prompt> tail error_log
- man

説明: format and display the on-line manual pages
使用例

prompt> man man

## 3. 課題

データ説明: とあるツイートリスト（2013/12/01-09）をダウンロードせよ(実験中のみダウンロード可。誤って削除したり欠席した学生は個別に連絡ください)。このファイルは1ツイートの関連情報が1行で保存されている。1行目は各項目の説明であり、実際のデータは2行目からTSV形式で保存されている。1番目はツイートID、2番目はユーザID、3番目はツイート日時、4,5番目はリプライ情報、6番目はscreen_name、7番目は名前、8番目はツイート本文、という順序で1ツイート関連情報が保存されている。

このツイートリストを読み込み、Level 1 では「ツイート数/日」をカウントしてグラフ化するためのスクリプトを作成する。Level 2 では mention map を描画するためのスクリプトを作成する。

Level 1: ツイートリストから「ツイート数/日」をカウントしてみよう。(当日時間次第では省略)

目的: 1日辺りのツイート数を求めたい。必要なデータを収集する手順はいろいろあるが、ここでは以下の手順で進める。

[日時抽出] ツイートリストから3番目の項目（日時）を抽出せよ。ヒント: cut。
[時分等の削除] 「yyyy-mm-dd hh:mm:ss+09」という形式で抽出されているはずだが、スペースから後半は不要である。前半の年月日のみを抽出せよ。ヒント: cut or sed。
[ノイズの除去] 先頭行に書かれていたコメント created_at も不要である。これを除外せよ。ヒント: grep。
[ツイート数のカウント] この時点で、日毎のツイート数＝「yyyy-mm-dd毎のツイート数（行数）」になっている。ユニークな行数毎に出現回数をカウントすることでツイート数をカウントせよ。ヒント: uniq。
[フォーマット集計] この時点で「ツイート数 yyyy-mm-dd」になっている。これをグラフ描画しやすくするため、「dd ツイート数」へと整形し、保存せよ。ファイル名は「daily.data」とする。ヒント: sed。
[gnuplot命令群の生成] daily.data を基に線グラフ or 棒グラフで「一日あたりのツイート数」を描画するための命令群を生成せよ。
[gnuplotコマンドを使ったグラフ生成]] gnuplotコマンドを用いてpdf/eps/svg形式でグラフ生成せよ。
[スクリプト化] 上記の処理をスクリプトとして整理せよ。

レポートに含める内容: (1)スクリプト本体、(2)実行結果(グラフ)、(3)スクリプトの解説。

Level 2: ツイートリストから mention map を作成してみよう。

目的: mentionツイートのみを対象とし、「AさんからBさんへメンションがあった場合にA->Bへ矢印を引く。矢印の太さはmention回数で決める」というmentionグラフを作成し、ユーザ間のmention関係を眺めてみたい。必要なデータを収集する手順はいろいろあるが、ここでは以下の手順で進める。

[screen_nameとツイート本文の抽出] ツイートリストからscreen_nameとツイート本文を抽出せよ。ヒント: cut コマンド。
[mentionツイートの抽出] 誰かへの mention として、ここでは「タブ@screen_name」というツイート、つまり@から始まるツイートだけを対象としたい。@から始まるツイートだけを抽出せよ。ヒント: grep コマンド。
[正規表現の検討]誰かへの mention は「ツイート本文において@から始まる」ように書かれているはずだ。つまり、先ほどの出力においては「screen_name1(タブ区切り)@screen_name2 ツイート本文」というパターンで記述されている。このパターンを正規表現で示せ。
[mention関係のみを抽出] 上記の正規表現を用いて「screen_name1 screen_name2」へと書き直せ。つまり、タブはスペースに変換し、ツイート本文を削除せよ。また、screen_name2の冒頭にある@を削除せよ。ヒント: sed。
[ノイズの除去] 上記の変換により基本的には「screen_name1 screen_name2」というパターンになっているはずだが、ノイズ（ここでは@を含むツイート）が含まれている。これを除外せよ。ヒント: grep。
[mention関係の集計] この時点で「screen_name1 screen_name2」のみとなっているが、これらは時系列に並んでいる。「AさんがBさんに何回mentionを送ったか」をどのように数えたら良いだろうか。ヒント: sort, uniq。
[集計結果のフォーマット整形] uniqでカウントすると、不必要なスペースが入る。これを整えるために「連続したスペースは1つに変換」せよ。ヒント: sed or tr。ここまでの結果を「mention.data」として保存するものとする。
[dot形式への変換] mention.dataは「 mention回数 screen_name1 screen_name2」の形式で記述されている。これをdot記述「"screen_name1" -> "screen_name2" [penwidth=mention回数];」に変換せよ。
[dot形式ファイルの作成] 前述の前後を適切に記述し、dot形式ファイルとして正しくなるよう処理を加えよ。ファイル名は「mention.dot」とする。ヒント: echo
[dotコマンドを使ったグラフ生成] dot コマンドを用いて pdf 形式でグラフ生成せよ。
[スクリプト化] 上記の処理をスクリプトとして整理せよ。

レポートに含める内容: (1)スクリプト本体、(2)実行結果(グラフ)、(3)スクリプトの解説。

## 4. オプション課題例

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

### (4.1 ゴミ箱の作成)

これを選択する学生があまりにも多く、サンプルも大量にあるので今回は加点低いです。それでも構わなければやってみてください。

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

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

### 4.2 バックアップスクリプトの作成

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

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

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

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

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

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

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

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

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

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

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

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

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

/etc/init.d/

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

なお Mac OS X の場合は、init.d に相当するものとして SystemStarter や launchd として用意されています。bashとは無関係になりますが、「デーモン（サービス）を起動するためのスクリプト」としては同じ枠組みですので、興味があれば調べてみると良いでしょう。

注意点として、スクリプト全体を1行ずつ全て解説する必要はありません。例えば、スクリプト内で関数が書かれていれば「この関数はホゲホゲしている」という程度のことが読み取れれば十分です。取り組んで、理解できた部分やできなかった部分を明示することで努力したことを読み取れるレポートにしてください。

例えば Web サーバ は /etc/init.d/httpd というスクリプトで起動/停止が可能である。
Linux 参考: Linux起動の仕組みを理解しよう
Mac OS X 参考: SystemStarter(8) Mac OS X Manual Page, OS X独自のコマンドたち(1), initを置き換えるlaunchd【前編】

### 4.7 サンプルスクリプトを読んでみる

當間の学科リポジトリの「sh-sample」に下記4つのサンプルを用意したので、これらを読んで解説してみる。

ヒント: postfix, sendmail コマンドについて調べる。
(1) ./ping_check.sh: 指定したホスト群に対してping試験し、オプションにより出力方法を切り替える。
(2) ./csv2htmltable.sh: csv出力を読み込み、HTMLのテーブル形式に変換する。
(3) ./text2mail.sh: 任意のテキストファイルをメール送信する。
(4) wget-yahoo/daily.sh: Yahoo!の天気ページをダウンロードし、最高気温を抽出する。cron.dailyを意識した例。

なお、上記の例(1),(2),(3)は組み合わせて使うことも可能です。

prompt> ./ping_check.sh -c nirai kanai naha shell www \\
| ./csv2htmltable.sh | ./text2mail.sh -t mail-address

### 4.8 Easy Package 本体スクリプトを読んでみる

Easy Packageの本体はPerlで書かれたスクリプトファイル(epkg)です。

whichコマンドでepkgがどこにあるかを確認してから、lessコマンド等で中身を覗いてみる。全部でなくて構わないので、少しずつ解読してみる。
epkgコマンドの使い方は、単に「epkg」として引数無しで実行すると確認することができる。例えばインストール済みパッケージを確認する場合には「epkg ls」、パッケージ一覧を眺めるには「epkg list」のように様々なオプションが用意されているが、それらのオプション切り替えはどのように実現されているだろうか。

prompt> which epkg
/usr/local/bin/epkg #大抵はここにあるでしょう。
prompt> less /usr/local/bin/epkg

## 5. レポート骨組み

LaTeXの使い方がまだ良くわかっていない学生のために、レポートの骨組みを用意しました。下記の「骨組み」では、section（節）、箇条書き（itemize）、スクリプトのような「記号を含む複数の行」をそのまま出力する例（verbatim）、図や表を含める例（figure,table）、参考文献の列挙（thebibliography）、図表や参考文献に付与したラベル名を用いた参照（label, ref, cite）といった、一般的なレポートに求められる使い方を一通り含んでいます。必要に応じて参考にしてください。

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

prompt> platex info1-script.tex
prompt> platex info1-script.tex
prompt> dvipdfmx info1-script.dvi
prompt> open info1-script.pdf
もしくは
prompt> make

### 参考文献・サイト

當間用意サンプル一覧

レポート骨組み: [ reportskel.tgz | PDF ]
サンプルスクリプト: [ sh-sample on Mercurial ]

sh(bash)スクリプト

シェル・スクリプト工房 by ITpro
＠IT：Linux Square

- 第8回 bashで始めるシェルスクリプト基礎の基礎
第9回 bashの便利な機能を使いこなそう
第10回 Linux起動の仕組みを理解しよう［init編］
最終回 Linux起動の仕組みを理解しよう［rc編］
- @IT: 連載記事 「ステップ・バイ・ステップ・シェルスクリプト」
cronの設定ガイド
書籍
- UNIX/Linuxシェルスクリプト マスタリングハンドブック
- Mac OS X のサービス起動関連

SystemStarter(8) Mac OS X Manual Page
OS X独自のコマンドたち(1)
initを置き換えるlaunchd【前編】

gnuplot関連

gnuplot入門
Gnuplot FAQ

ImageMagick関連

Imagemagickの使い方

その他

yumとは？
X Window System