シェルスクリプトと実行権限
シェルスクリプトは、いつも端末に打っているコマンドをファイルにまとめて一気に実行する仕組みです。1行目に #!/bin/bash のような「シバン」を書くと、どのインタプリタで動かすかをOSに伝えられます。作ったファイルには chmod +x で実行権限を付け、./script.sh のように実行します。権限を付けずに動かしたいときは bash script.sh と明示的にインタプリタを指定する方法もあります。
ターミナルで毎日打っているコマンドは、その場で一度きり実行されて消えていきます。けれども同じ手順を繰り返すなら、コマンドをテキストファイルに上から順に書き並べておき、そのファイルを呼び出すだけで一気に流せるようにすると、手間も打ち間違いも一気に減ります。この「コマンドを並べたテキストファイル」がシェルスクリプトです。実体はただのテキストなので、専用の開発環境は要りません。vi や nano のようなエディタと、実行するためのターミナルさえあれば今すぐ始められます。簡単な定型作業の自動化から、条件分岐や繰り返しを織り込んだ小さなプログラムまで、同じ仕組みの延長で書けるのがシェルスクリプトの強みです。
まずは中身を1行か2行だけ持つ最小のスクリプトを作って、それを動かすところまでを通してみるのが理解の近道です。たとえば hello.sh という名前で、画面に文字を出すだけのファイルを作ってみましょう。echo は引数の文字列を標準出力へ表示するコマンドで、$USER は今ログインしているユーザ名に置き換わる変数です。
シバンでインタプリタを指定する
スクリプトファイルの1行目には、ほぼ必ず #!/bin/bash のような行を書きます。これをシバン(shebang)と呼びます。シバンは「このファイルの中身を、どのプログラム(インタプリタ)に解釈させるか」をOSへ伝える道しるべです。#!/bin/bash と書いておけば、ファイルを直接起動したときに /bin/bash がその内容を読んで実行してくれます。先頭の #! という2文字は特別な記号で、ここだけはコメントではなく命令として扱われます。2行目以降に出てくる # は、これとは違ってその行をコメント(説明用のメモ)にする普通の記号です。シバンを書かずに実行すると、どのシェルで動くかが環境任せになり、思わぬ誤動作の原因になります。だからこそ1行目のシバンは習慣として必ず付けます。
シバンには #!/bin/bash のように絶対パスで bash を直接指す書き方のほかに、#!/usr/bin/env bash という書き方もよく使われます。env を経由すると、PATH の通った場所から bash を探して起動するため、bash が置かれている場所が環境によって違っても動きやすくなります。どこでも動く移植性を重視するときに役立つ書き方として覚えておくとよいでしょう。
実行権限を付けて ./ で起動する
テキストファイルを作っただけでは、まだ「実行してよいファイル」とは見なされません。スクリプトを起動できるようにするには、実行権限(x)を chmod +x で与える必要があります。chmod +x hello.sh と打てば、そのファイルに実行権限が付きます。権限が付いたかどうかは ls -l で確認でき、行頭のパーミッション表示に x が現れていれば実行可能な状態です。逆に実行権限が無いまま起動しようとすると Permission denied(許可がありません)というエラーが出ます。これは初学者がほぼ必ず一度はつまずく場面で、出たら落ち着いて chmod +x を実行すれば解決します。
起動するときは、ファイル名の前に ./ を付けて ./hello.sh のように打ちます。./ は「今いるフォルダ(カレントディレクトリ)にあるこのファイル」という意味です。実際の流れは次のようになります。
$ chmod +x hello.sh / $ ./hello.sh と続けて打つと、画面に Hello, user01 のように、$USER が実際のユーザ名へ置き換わった結果が表示されます。ここで注意したいのが、./ を付け忘れて hello.sh とだけ打つと command not found(コマンドが見つかりません)になることがある点です。シェルはコマンドを PATH に登録された場所からしか探さず、カレントディレクトリは自動では探しに行きません。そのため「ここにあるこれを実行して」と場所を明示する ./ が必要になるのです。この挙動を知らないと「ファイルは確かにあるのに動かない」と戸惑いがちなので、最初に理解しておくと回り道が減ります。
実行権限を付けずに動かす方法
実行権限を付けなくてもスクリプトを動かす方法があります。bash script.sh のように、インタプリタである bash を先に書き、その引数としてスクリプトファイル名を渡すやり方です。この場合はファイルに x が無くてもかまいませんし、極端に言えば1行目のシバンが無くても bash が解釈してくれます。一時的に動作を試したいときや、他人から受け取ったスクリプトを実行権限を変えずに走らせたいときに便利です。同じように sh script.sh とすれば sh で実行できますが、その場合は bash 独自の機能が使えない、より素朴なシェルとして動く点には注意が必要です。
似て非なるものに source(または .)があります。source script.sh は、新しいシェルを立ち上げずに「今いるシェルそのもの」でスクリプトの中身を読み込んで実行します。./script.sh や bash script.sh が別プロセスのシェルを起動して実行するのに対し、source は現在のシェルに直接効くため、スクリプト内で設定した変数や cd による移動が、実行後の手元のシェルにも残ります。設定ファイル(~/.bashrc など)を読み直すときに source ~/.bashrc とするのは、この性質を利用したものです。「別の場所で動かしたいなら ./ や bash、今のシェルに反映させたいなら source」と整理しておくと使い分けに迷いません。実務では、毎回 alias を打ち直す代わりに ~/.bashrc に書いておき、ログインのたびに自動で読み込ませる、といった形で source の性質が活きています。
ここまでをひとつの流れにまとめると、シェルスクリプトを動かす手順は「エディタで中身を書く→1行目にシバンを書く→chmod +x で実行権限を付ける→./ を付けて起動する」の4ステップになります。動かないときの代表的な原因も決まっていて、Permission denied なら実行権限の付け忘れ(chmod +x で解決)、command not found なら ./ の付け忘れ(場所の明示で解決)、思った挙動にならないならシバンの書き忘れや誤り、というように切り分けられます。この対応関係を頭に入れておけば、最初のスクリプトでつまずいても自力で立て直せます。