シェルスクリプト入門
シェルスクリプトとは
シェルスクリプトは、シェルのコマンドラインを、あらかじめ記述しておくファイルのことです。
シェルスクリプトを利用すると、シェルのコマンドを多用するような手順の自動化が行えます。
シェルスクリプトのメリットは以下の通りです。
- GUIの操作はだれかがその場で行う必要がありますが、シェルスクリプトは事前に作成したものを実行するだ
けで処理が完了するため、作業時間の大幅な短縮と操作ミスの防止が実現できます。 - シェルスクリプトは手動で実行することもできますが、あらかじめ決まった日時に自動実行させることもできま
す - 一度シェルスクリプトを作れば、あとで同じ処理が必要になった時に、そのシェルスクリプトを再利用できます
- 自分だけでなく、他の人にも、シェルスクリプトを配布して使ってもらうことができます。インターネットでも、さま
ざまなユーザが便利なシェルスクリプトの例を公開しているので、自分の環境に合わせてカスタマイズして利
用できます。
シェルの選択(参考)
シェルスクリプトは、名前の通りシェルの機能です。このため、シェルによっては同じことを行う場合でも、書き方が変
わる場合もあります。
一般的なのはshまたはbashですが、最終的にどのシェルを選択するかは環境に依存します。
なお、shとbashのどちらを使用するか?に限定した場合は、以下のような意見があります。
<shを推奨する意見>
• 過去のシェルスクリプトの多くがsh向けに書かれており、すべてのLinuxには必ずshが存在する
• このため、一般的には互換性・移植性に配慮し、sh向けに書いたほうが良い。
<bashを推奨する意見>
• shはディストリビューションごとにバラバラであり、その動作も若干変わってくる
RedHat系ディストリビューションは、shをbashの別名として実装し、shモードで動作させている
Debian系ディストリビューションでは、shをdashという原始的なシェルとして実装している
• bashはGNUプロジェクトによる実装のものしかなく、現代のLinuxでは、bashはほぼデフォルトでインストー
ルされているので互換性・移植性は高い
• bashにはシェルスクリプトを書く上で便利な機能が多く用意されている
シェルスクリプトを作成する
端末を起動し、以下の手順に従い、duコマンドの実行例を確認しましょう。
1. user01のホームディレクトリに保存されているファイルの合計サイズを確認します。
-s :合計のみ出力、-m :MB単位で表示
$ cd
$ du -sm
2. カレントディレクトリ内のファイルまたはディレクトリ単位で合計サイズを表示し、サイズの大きい順に並び替え、
先頭が0の行は省略して表示します。
$ du -sm * | sort -nr | grep ^[1-9]
以下の手順を実行し、シェルスクリプトの作り方を確認していきましょう。
1. ホームディレクトリにカレントディレクトリを変更します。
$ cd
2. ホームディレクトリに、テキストエディタのgeditかVimを使用して、シェルスクリプトを作成します。
※シェルスクリプトには、ファイル名の末尾に.shを付けると分かりやすく、管理がしやすくなります。
$ gedit size.sh
または
$ vim size.sh
3. エディタ内に、シェルスクリプトで実行したいコマンドを入力します。
以下のように入力してください。
#!/bin/bash
cd
du –sm
du -sm * | sort -nr | grep ^[1-9]
4. 上書き保存後、テキストエディタを終了します。
5. シェルスクリプトを実行するには、シェルスクリプトファイルに実行権限を与える必要があります。
$ chmod +x size.sh
6. カレントディレクトリ(現在はホームディレクトリ)内のシェルスクリプトsize.shを実行します( ./はカレントディ
レクトリを表しています)。
$ ./size.sh
作成したシェルスクリプトを編集して、表示結果をもう少しわかりやすくします。
編集後のシェルスクリプトsize.shの実行結果は、以下のようになります。
<編集後のsize.shの実行結果例>
20xx年 xx月 xx日 x曜日 xx:xx:xx JST ※シェルスクリプトを実行した日時を表示します。
Home directory size(MB) : 103 ※合計値の前に簡単な説明文を追加します
Details : ※ここにも簡単な説明文を追加します
15 sample.tar
15 sample.bak
(以下省略)
編集手順は以下の通りです。
1. 現在のsize.shをバックアップとして保存しておきます。
$ cp size.sh size.sh.bak
2. 任意のテキストエディタで、以下のようにsize.shを編集します。
※下線の付いている3、4、6行目のコマンドを追加します。
#!/bin/bash
cd
date
echo -e "¥n Home directory size (MB): ¥c"
du –sm
echo -e "¥n Details :"
du -sm * | sort -nr | grep ^[1-9]
3. 上書き保存し、テキストエディタを終了します。
4. シェルスクリプトを実行します。
$ ./size.sh
※ パーミッションは、既に設定済みなので再設定する必要はありません。
シバン(シェバン)
シェルスクリプトの最初の行に記入した、#!/bin/bash は、シバン(またはシェバン)といいます。
シェルスクリプトは、最初の行にシバンを記述する場合としない場合とで、実行方法が異なります。
<シバンを記述した場合>
シバンを記述したシェルスクリプトは、すでに学習したように以下のように指定すれば実行できます。
$ ./size.sh
シバンは、 「このシェルスクリプトは/bin/bashで動かします」という宣言を表すものです。たとえば、size.shの先頭
行に #!/bin/bash というシバンを記述しておくと、Linuxカーネルがシバンを解釈し、実質的に
「/bin/bash ./size.sh」というコマンドラインとして実行します。
<シバンを記述しない場合>
一方、シバンのないシェルスクリプトを実行する場合は、現在のシェルを確認し、シェルスクリプトを実行したいシェルに
切り替えた上で、sourceコマンドを以下のように実行します。
$ echo $SHELL 現在のシェルを確認
/bin/bash この実行結果例では、bashが現在のシェルであることがわかる
$ source ./size.sh
=====================
sourceコマンドは、指定したファイルの内容をそのままコマンドラインに入力したときと同じようにシェルスクリプトを実
行します。この場合は、シェルとシェルスクリプトの間にsourceコマンドが入る(シェルが直接スクリプトを実行するわ
けでは無い)ので、シェルスクリプトファイルに実行権限を割り当てる必要はありません 。
=====================
また、sourceコマンドと同じ意味を持つコマンドとして、「.(ドット)」コマンドがあります。この場合は、以下のように
指定し、実行します。
$ . ./size.sh
上記の例の、先頭の「 . 」がドットコマンドです。そのあとに続く「 ./」はカレントディレクトリを表します。
シェルスクリプトの書き方(参考)
シェルスクリプトは、内容を記述して目的通りの動作をすれば、どのように記述してもかまいません。
ただし、後から編集しやすいか?わかりやすいか?などは書き方によって左右されます。自作したシェルスクリプトも、1か月以
上経過すれば他人が書いたものとほとんど変わりません。このため、後でだれが見ても見やすく書くことを心がけると良いでしょう。
たとえば、以下の3行をシェルスクリプトで記述する場合を考えてみましょう。
例) echo "root directory"
cd /
ls -l
上記の3行は、以下のように記述することもできます。
1. 「;」で区切ると、複数のコマンドを1行で記述できます。
echo "root directory" ;cd / ;ls -l
2. バックスラッシュで改行できます。実行時は1行として扱われます。
echo ¥ (¥を入力すると、画面にはバックスラッシュが表示されます)
"root directory"
シェルスクリプトでは、コマンドをパイプラインでつなげる処理もよく利用しますが、パイプラインの直後に改行を含めることもでき
ます。
3. パイプラインの直後で改行できる(sort file3 | uniq -c の例)。
※ カレントディレクトリを~/sampleに変更後実行してください
sort file3 |
uniq -c
シェルスクリプトでどのような処理をするのか、なぜこの処理が必要なのか?などの注釈を入れてわかりやすくする場合は、#記
号を使うと、#記号以降がコメントとしてシェルスクリプトの処理から除外されるようになります。
4. #を書くと、その行の終わりまでがコメント(注釈)扱いになります。
# ルートディレクトリに移動する
cd
ls -l #ファイルサイズなども表示する
シェルスクリプト練習問題1(MUST)
次の要件を満たすようなシェルスクリプトの作成を行い、実際に実行して確認してください。
(本演習はuser01で行ってください)
<要件>
- シェルスクリプト作成の準備として、ホームディレクトリにmkdirコマンドで「scripts」という名前のディレクトリを作
成し、touchコマンドで「test.txt」という名前の空のファイルを作成します
※ touchコマンドは、存在しないファイル名を指定するとその名前で空のファイルを作成します。
また、存在するファイル名を指定すると、そのファイルの更新日付をtouchコマンドを実行した日時に更新
します。 - test.txtのファイルの更新日付をtouchコマンドで更新するシェルスクリプトを、scriptsディレクトリにsh01.shと
いう名前で作成してください。 - シェルスクリプトが正しく動作しているかは、sh01.shスクリプトを手動で実行した後、 test.txtを、
ls --full-timeで参照したときに、sh01.shを実行したときの時間が表示されるかどうかで判断してください。
==============================
OnePoint
複雑なシェルスクリプト
シェルスクリプトは、条件分岐や繰り返しなどの複雑な処理も行えます。今後プログラミングの学習を進めていった後に、
もう一度シェルスクリプトを振り返ると、シェルスクリプトが理解しやすくなります。
==============================
シェルスクリプト練習問題2(SHOULD)
次の要件を満たすようなシェルスクリプトの作成を行い、実際に実行して確認してください。
(本演習はuser01で行ってください)
-
<要件>
- /home/user01/sample/log/web.logファイルを解析するシェルスクリプトをホームディレクトリのscriptsサブ
ディレクトリに作成します。
※ sample/log/web.logファイルは、Webサーバのアクセス履歴ファイルです。 - ファイル名は、sh02.shにしてください。
- sh02.shを実行すると、sample/log/web.logファイルの中の、iPhoneという文字列を含む行の行数を表示
するように、シェルスクリプトを構成してください。
grepコマンドとwcコマンドを利用すると、ファイル内の特定の文字列を含む行の数を簡単に表示できます。
※このスクリプトを実行すると、iPhoneユーザのアクセス数(647件)がカウントできます。
シェルスクリプトを自動実行する
シェルスクリプトは手動で実行することもできますが、指定した日時に自動的に実行させることもできます。
自動実行をさせる場合は、cronを利用します。cronは、crond(cronデーモン)がインストールおよび実行されてい
る必要があります。
cronは、管理者権限か、管理権限のない一般ユーザのいずれかで、指定したコマンドやシェルスクリプトを実行すること
ができます。
- 管理者権限で定期実行させるジョブ(コマンドやシェルスクリプトなど)を設定する場合
- 一般ユーザーで定期実行させるジョブを設定する場合
/etc/crontab(cronの設定ファイル)をテキストエディタで直接編集し、自動実行の設定を行います。
各ユーザーに用意されたcrontabファイルを編集します。
crontabファイルは、crontab -eで編集を行います。
crontab -eの書式は,/etc/crontabファイルとほぼ同じですが、以下の点が異なります。
<異なる点>
• ユーザー名の指定ができない
• 記述内容が /var/spool/cron/ユーザー名 のファイルに記録される
• 一般ユーザーにはこのファイルに対するアクセス権が割り当てられていないため、内容の確認は crontab –l
で行う
• crontab –l を管理者権限で実行すると、全ユーザーの設定が確認できる
==============================
OnePoint
crontab -e
crontab -eコマンドを実行すると、本環境ではvimが起動し、設定ファイルを編集します。
テキストエディタを変更する場合は、EDITORという環境変数に任意のテキストエディタを指定します。
==============================
以下の手順を実行し、作成したシェルスクリプトsize.shを、定期的に実行するようにcronを設定します。
1. 最初に、crond(cronデーモン)が起動していることを確認します。
Active: active (running) という表示があれば、起動しています(systemctlコマンドは、7章で学習します)
$ systemctl status crond
2. crontabを編集します。以下のコマンドを実行すると、設定ファイルが読み込まれた状態でVimが起動します。
$ crontab -e
3. 以下のように入力し、1分おきにsize.shが自動実行され、最新の実行結果がホームディレクトリのsize.txt
に保存されるように構成しましょう。
以下は、*も含めて、すべて半角で入力します。*の後ろには、すべて半角スペースを入力してください。
* * * * * /home/user01/size.sh >/home/user01/size.txt
4. 上書き保存し、crontab –eを終了します。
5. 設定が保存されたことを確認します。
$ crontab –l
* * * * * /home/user01/size.sh >/home/user01/size.txt
6. 1分程度端末を放置し、シェルスクリプトが自動実行された結果が、ホームディレクトリのsize.txtに記録されてい
ることを確認します(シェルスクリプトが正しく記述されており、crontab -e で正しくシェルスクリプトが指定さ
れていなければ、以下のコマンドを実行しても何も表示されません)。
$ cat size.txt
7. 確認ができたら、もう一度crontab –eを実行し、設定を消去後上書き保存して終了します。
$ crontab –e
※ファイル内の手順3で入力した行(* * * * * /home/user01/size.sh
>/home/user01/size.txt)を削除後、上書き保存して終了します。
変数の利用
変数(variable)は、プログラムやシェルスクリプトの中で、データを一時的に記憶しておくための領域に名前を付けたもので
す。プログラミングでは変数は不可欠の機能ですが、シェルスクリプトでも変数を利用できます。
変数は4章で学習しましたが、シェルスクリプトでも変数を利用することがあるため、シェル変数の復習をしましょう。
シェル変数は、環境変数とは異なり、現在実行しているシェルの中だけで有効な変数で、シェルスクリプトの中では、以下のよ
うに定義します。
変数名=値
定義したシェル変数を利用するときは、変数名の前に$記号を付けます。
$変数名
また、変数をシェルスクリプト内で扱うときに、以下の点に特に注意しましょう。
・ 値の代入時は変数名に$を付けない
・ =の前後にスペースを入れない
・ 変数名に利用できるのはアルファベット、数値、_(アンダースコア)だけ
・ 変数名の1文字目に数値は使えない
・ 変数名を{}で囲むと、変数名とほかの文字列の区切りが明示できる
たとえば、以下のシェルスクリプトを作成して実行すると、変数wordにセットされた値であるHelloが表示されます。
#!/bin/bash
word=Hello =====> シェル変数wordに、値 Helloをセット
echo $word =====> シェル変数wordにセットされた値 Helloを表示
なお、シェルスクリプトに限った話ではありませんが、変数名をシングルクォーテーションで囲んだ場合と、ダブルクォーテーションで
囲んだ場合では動作が異なります。たとえば、以下のシェルスクリプトを作成して実行すると、'(シングルクォーテーション)で
囲んだ変数名は、変数名ではなく単なる文字列として扱われます。一方、"(ダブルクォーテーション)で囲んだ文字列は
シェルによって変数が展開され、変数にセットされた値が表示されます。
#!/bin/bash
word=Hello
echo $word ====> Hello と表示される
echo "$word" ====> Hello と表示される
echo '$word' ====> $word と表示される
コマンド置換
コマンド置換とは、コマンドの実行結果を文字列として取得するときに利用します。
コマンド置換を行う場合は、コマンドを $(コマンド) のように $() で囲むか、`(バッククォート)で囲みます。
たとえば、本日日付をファイル名にして新規作成する場合は、以下のように指定できます。
以下の例では、本日日付を表示するdateコマンドで、年-月-日形式(コマンドの‘+%Y-%m-%d’で指定)の
本日日付を算出し、 filenameというシェル変数を定義して値を代入しています 。その後、この値を使用し、カレ
ントディレクトリにdiaryで始まる、ファイルの作成年月日の入ったファイル名のファイルを作成しています。
cd
filename=$(date '+%y%m%d') または filename=`date '+%y%m%d'`
touch diary$filename
ls diary*
変数を利用しない場合は、以下のようになります。
touch diary$(date '+%y%m%d') または touch diary`date '+%y%m%d'`
以下の例では、本日日付を表示するdateコマンドで、年-月-日形式(コマンドの‘+%Y-%m-%d’で指定)で日付を
取得し、Today is の後ろに直接表示しています(Today is 2018-01-12のように表示されます)。
echo Today is $(date '+%Y-%m-%d')
位置パラメータ(参考)
シェルスクリプトを実行時に、シェルスクリプト名の後に文字などを指定し、シェルスクリプトに値として渡すことができます。この値のこと
を引数といいます。シェルスクリプトでは引数を「位置パラメータ」と呼ぶ特殊な変数に代入しているので、シェルスクリプトから引数を
利用するときは、位置パラメータを指定します。
たとえば、以下のようにシェルスクリプトを実行した場合、1つめの引数「apple」を取り出す場合は$1を、「orange」を取り出す場
合は$2をシェルスクリプト内で指定します。
./script.sh apple orange
1つ目の引数appleをシェルスクリプトで参照するときは、位置パラメータ$1を指定する
2つ目の引数orangeをシェルスクリプトで参照するときは、位置パラメータ$2を指定する
引数で指定したディレクトリ名でホームディレクトリにサブディレクトリを作成するシェルスクリプトを作ってみましょう。
1. dir.shという名前で、ホームディレクトリにテキストファイルを作成します。
$ cd
$ vim dir.sh または gedit dir.sh
2. 以下のシェルスクリプトを入力します($1は、1つめの引数を表し、$0はシェルスクリプト名を表します)。
上書き保存後、終了します。
#!/bin/bash
cd
mkdir $1
echo $0 complete!
3. 作成したシェルスクリプトに、実行アクセス権を追加します。
$ chmod +x dir.sh
4. シェルスクリプトを実行します。以下のように入力すると、testdirというディレクトリが作成され、「./dir.sh complete!」という
メッセージが表示されます。
$ ./dir.sh testdir
./dir.sh complete!
5. lsコマンドで、testdirディレクトリが作成されたことを確認します。
$ ls -ld testdir
6. 【練習問題】カレントディレクトリにある、引数で指定したファイルやディレクトリを削除するシェルスクリプトremove.shを作成し
てみましょう。
シェルとサブシェルの関係(参考)
上図の「 ./size.sh 」のように、ファイル名でシェルスクリプトを実行した場合は、サブシェルでシェルスクリプトが実行され
ます。
サブシェルとは、現在のシェルから新しく起動される子プロセスのシェルのことです。
サブシェルは元のシェルとは別のものとして扱われるため、エイリアスなどの設定がサブシェルには引き継がれません。このた
め、上図のようにシェルスクリプト内に、サブシェルに引き継がれない機能(エイリアスなど)を含めると、シェルスクリプトが
正常に実行されない現象が起こります。
一方で、sourceコマンドの場合はサブシェルを起動しません、カレントシェルでシェルスクリプトを実行するので、上記のよ
うなことはありません。
sourceコマンドの注意点(参考)
sourceコマンドの場合はサブシェルを起動せずに、カレントシェルでシェルスクリプトを実行します。このため、上図のよう
に、シェルスクリプト内で指定したエイリアスなどが、シェルスクリプト実行後も残ってしまう、という現象が起こります。
この動作が問題ない場合は気にしなくてもかまいませんが、スクリプト内でのみ使用し、スクリプト終了後に残したくない
設定がある場合は、シェルスクリプトの中に不要な設定を消去する命令を追加しておく必要があります。
このように、シェルスクリプトは実行方法によって動作が変わるので、シェルスクリプトを書くときと実行するときの両方
に注意して記述しましょう。
シェルスクリプトの実行形式(参考)
一般的に、多くのシェルスクリプトは以下の理由から、sourceコマンドではなく「./size.sh」のようなファイル名を指定し
た形式で実行されます。
<理由>
- シバンでシェルを指定することで、ユーザのシェルが何であっても正常に動作させることができる
- sourceコマンドによる実行は、元のシェルの状態を引き継ぐため、シェルの設定の違いによってシェルスクリプト
作成時には想定していなかった動作をすることがある - 前ページで述べたように、シェルスクリプト終了後のシェルにも影響を及ぼしてしまう可能性がある
==============================
参考
sourceコマンドの利用例としてはbashの設定ファイルで、ホームディレクトリにある.bashrcファイルがあります。
bashの設定ファイル~/.bashrcはシェルスクリプトです。~/.bashrcは、~/.bash_profileから、sourceコマン
ドで読み込まれるように設定されています。目的は、シェル設定のカスタマイズを、カレントシェルに反映させるためで
す。このような構成にしておくと、複数のシェルスクリプトから同一の値を参照させることができるようになるので便利
です。
==============================