はうすてんぼぶ

コードかいてて疑問に思ったことや、興味あることをつらつらと暇なときに書く場所、ここはそんな場所

シェルスクリプトを書いてみよう 基礎編

あまりシェルスクリプトを書いたことが無かったので、基本的なとこを勉強しつつ触ってみる。

コマンドラインで書いていることを、スクリプトに書いておけば楽できる、みたいな感覚。

とりあえず、基礎的な部分として、書き方と実行方法、引数の渡し方、定期実行の方法あたりに今回は触れます。

とりあえず

zsh上で、ファイルにコマンドを書いて実行してみた。

% echo "echo \"Hello World\"" > shell_file
% zsh shell_file
Hello World

これだけだと寂しいので、実行するとホームディレクトリに飛んで、lsを実行してくれるようなものを書いてみた。

% cat gohome
cd ~/
pwd
ls

これを実行すると、ホームディレクトリの現在の場所が表示された後に、ファイル一覧が表示される。

が、その実行方法によってちょっと異なる点がある。

シェルスクリプトの実行方法には、以下の3つがある。

source [script_name]
. [script_name]
zsh [script_name]

上のsourceと.で実行する場合は、現在の環境でそのスクリプトを実行する。
zsh(環境によってはbashだったりする)で実行すると、新しいシェルが起動してそこでスクリプトが実行される。

新しいシェルを起動して実行した場合は以下のようになる。

% pwd
/home/bob/example

% zsh gohome
/home/bob
ダウンロード
テンプレート
〜〜〜 省略 〜〜〜

% pwd
/home/bob/example

現在の場所が変わっていないことが分かる。
これは、新しいシェルでカレントディレクトリは移動したが、元の環境でcdが実行されていないため。

sourceで実行した結果は以下のようになる。

% pwd
/home/bob/example

% zsh gohome
/home/bob
ダウンロード
テンプレート
〜〜〜 省略 〜〜〜

% pwd
/home/bob

現在のシェルで実行すると、cdによって現在場所も変わったことがわかる。

ファイルモードで実行を可能にする

シェルスクリプトを実行すうrときに、毎度毎度sourcezshと書くのは結構手間だったりする。
そういったときは、chmodを用いて、そのスクリプトファイルを「実行許可ファイル」に設定すれば、ファイル名だけでスマートに起動できる。

chmod +x [shell_script]
chmod u+x [shell_script]

これで、[shell_script]に、スクリプトファイルを指定すれば実行許可ファイルになる。「+x」だと全ユーザでそのファイルを実行可能になり、「u+x」だとユーザ本人だけが実行可能になる。

さっき書いたシェルスクリプトのgohomeファイルを使って、以下に例を書く。

% gohome
zsh: command not found: gohome

% chmod u+x gohome

% gohome
zsh: command not found: gohome

% ./gohome
/home/bob
ダウンロード
テンプレート
〜〜〜 省略 〜〜〜

% pwd
/home/bob/example

注意したいのが、実行許可ファイルにした場合は、新しいシェルが起動してそこでシェルスクリプトが実行されるということである。
上の例では、gohomeを実行許可ファイルにし実行してみたが、最後のpwdcdが適用されていないことがわかる。

起動シェルの指定

シェルスクリプトを実行許可ファイルにすると、一つ問題が発生する。
というのも、今の環境と同じシェルが起動して、そこでシェルスクリプトが実行されるので、もしそのシェルスクリプトが別のシェル環境用に書かれていた場合には動かない場合がでてくる。

なので、シェルスクリプトの一行目にシバン(shebang)を書いておくことで、スクリプトを読み込むインタプリタを指定することができる。
シバンは、#!で書き始める必要がある。

なのでさっき書いたgohome(本来の名前の役割はもう果たせないけれども…)も最初にzshで実行して欲しい!ってことをシバンで書いておく必要がある。

% cat gohome
#! /bin/zsh
cd ~/
pwd
ls

なぜ、パスを書かなきゃいけないかというと、別のシェル環境が/binをPATHに設定していない場合でも実行可能にするため、だと思う。

引数の渡し方

引数を渡す場合は、

% source [script_file] [arg0] [arg1] ...

のように、[arg0]、[arg1]のように半角スペースを開けて渡す。

スクリプト側で、その引数を参照するためには、以下の3つの方法がある

名前 説明
$@ 全引数
$* 全引数(環境変数IFSで示す文字で区切る)
$# 引数の数
${n} n番目の引数(0はコマンドラインの先頭名が入る)

n番目の引数を参照する際、nが一桁なら{}は不要。ただ、${2}のようにしても問題ないので、{}常時{}で囲む癖を付けといたほうが良いのかも。

以下のようなファイルを準備して実行してみた。

% cat argtest_file1
#! /bin/zsh
echo "0: ${0}"
echo "1: ${1}"
echo "2: ${2}"
echo "#: $#"
echo "@: $@"
echo "*: $*"

実行結果は以下の通り。

% ./arg_file hoge fuga
0: ./arg_file
1: hoge
2: fuga
#: 2
@: hoge fuga
*: hoge fuga

それ以外にも以下のような特殊変数がある。

名前 説明
$? 最後に実行したコマンドのexit値
$$ プロセスID
$! シェルが最後に起動したバックグラウンドプロセスのプロセスID
$- シェルの起動時のフラグ、setコマンドを使って設定したフラグの一覧

定期的に実行したい場合

作ったシェルスクリプトを定期的に実行したい場合はcrontabを使う。

crontabコマンドに入力すると、それが設定ファイルに書き込まれるので、

% echo "*/1 * * * * /home/bob/example/logDate" | crontab
% crontab -l
*/1 * * * * /home/bob/example/logDate

のようにすれば設定できる。
または、crontab -eでviを起動して直接記述しても良い。

設定書式は、以下のようになっている。

[minute] [hour] [date] [month] [day_of_week] [path]

[minute]: 分(0-59)
[hour]:時(0-23)
[date]:日(1-31)
[month]:月(1-12)
[day_of_week]:曜日(0-7)
[path]:実行したいコマンド(シェルスクリプトファイル)へのパス

設定した値になった際に、[path]のコマンドが実行される。
例えば、以下のようにすると毎時10分のときにhogeが実行される。

10 * * * * /home/bob/hoge

*は、そのフィールドで取りうるすべての値を表現する。
また、ダッシュやコンマを用いることで、範囲指定やリストを指定できる。

10,20,30 * * * * hoge (毎時10分、20分、30分のときに実行)
10-30 * * * * piyo (毎時10分〜30分の間は毎分実行)
5,10,20-30 * * * * fuga (毎時、5分と10分と20〜30分の間に実行)

間隔設定をしたい場合は/を使う。
15分ごとに実行したい場合は、

*/15 * * * hoge

とする。

以下のようなlogDateという現在時刻をファイルに追記する実行ファイルを作っておいて、crontabに登録した例を示す。

% cat logDate
#! /bin/zsh
date >> ~/log.txt

% echo "*/1 * * * * /home/bob/example/logDate" | crontab

〜 3分後 〜

% cat ~/log.txt
2012917日 月曜日 21:43:02 JST
2012917日 月曜日 21:44:02 JST
2012917日 月曜日 21:45:01 JST

crontab -rで、現在のcrontabを削除する(全ての設定を削除)。
個別に不要になったものを削除する場合には、crontab -eで編集モードで行ごと削除するようにしよう。

  • rのオプションは誤爆すると危険なので、シェルの設定ファイルに以下のaliasを追加しとておくと安心安全。
alias crontab='crontab -i'

こうすることで、crontabの削除が行われそうになっても確認がでるようになる。

終わりに

今回はシェルスクリプトの基礎的なとこを書いてみた。
追々もっと深くまで勉強する必要はあるが、とりあえずここまで。

参考資料

Amazon.co.jp: 改訂 新Linux/UNIX入門: 林 晴比古: 本, Chapter 26 シェルプログラミング.
引数処理 シェルスクリプトサンプル, http://www.unix-vm.com/command4_7.html.
UNIXの部屋 コマンド検索:crontab (*BSD/Linux), http://x68000.q-e-d.net/~68user/unix/pickup?crontab.
crontabの書き方 — server-memo.net, http://nweng.wiki.fc2.com/wiki/crontab%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9.