第6章 6-2 / シェルの力

初めてのシェルスクリプト

このページで叩くコマンドと到達点

前提:6-1が完了し、ホームディレクトリにいる状態から始めます。6-1では変数という「箱」の使い方を覚えました。このページではいよいよ、複数のコマンドを1つのファイルにまとめて、名前を打つだけで一気に実行できるシェルスクリプト※1を自分の手で書きます。専用の作業場~/scriptsを作り、そこに最初のスクリプトhello.shを書き、実行権限を与えて動かし、最後にはキーボード入力を受け取るgreet.shまで作ります。~/scriptsはこの先第6章の残りのページでずっと使う場所です。

このページではSET 1〜3、合計30行のコマンドを上から順に叩きます。手打ち推奨(コピーは確認用)です。

SET 1 ― scriptsディレクトリとhello.shを書く

ubuntu@lightsail: ~
  1. $mkdir ~/scripts
  2. $cd ~/scripts
  3. $pwd
  4. /home/ubuntu/scripts
  5. $ls
  6. $nano hello.sh
  7. (#!/bin/bash から始まる下のスクリプトを入力し保存)
  8. $cat hello.sh
  9. #!/bin/bash
  10. echo "Hello, Linux Drill!"
  11. echo "今のユーザーは $USER です"
  12. $file hello.sh
  13. hello.sh: Bourne-Again shell script, ASCII text executable
  14. $wc -l hello.sh
  15. 3 hello.sh
  16. $head -1 hello.sh
  17. #!/bin/bash
  18. $ls -l hello.sh
解説 ― SET 1 で何をしたか

1行目のmkdir ~/scriptsで、これから第6章の残り全部で使うスクリプト専用ディレクトリを作ります。第1章の~/practiceと同じ位置づけで、ここに書いたスクリプトは章の最後まで残しておきます。23行目で中へ移動して現在地を確認し、4行目のlsでまだ何も無い空のディレクトリであることを確認します。

5行目のnano hello.shでエディタを開き、下のターミナルブロックに示した3行を入力して保存します。catで見えている中身の1行目#!/bin/bashシバン※2と呼ばれる特別な1行で、「このファイルは/bin/bashというプログラム(bashシェルそのもの)に読み込ませて実行してください」という宣言です。シバンは必ずファイルの1行目に書き、これが無いとスクリプトが正しく解釈されないことがあります。

2行目・3行目のechoは第0章から使ってきたおなじみのコマンドで、これをファイルの中に順番に並べておくだけで「複数のコマンドをまとめて実行する」というスクリプトの基本形が完成します。3行目では6-1で学んだ環境変数$USERを使い、実行したユーザー名を表示するようにしています。

7行目のfile hello.sh(第1章1-4で学習済み)を実行すると、出力例のとおりシバンのおかげでこのファイルが「シェルスクリプトである」ことをLinux自身が認識してくれていることがわかります。8行目のwc -lで行数を確認すると3行、9行目のhead -1(第1章1-4で学習済み)で先頭1行だけを表示すると、確かにシバンが書かれていることが裏付けられます。10行目のls -l hello.shで権限を確認すると、-rw-r--r--のようにxの実行権限が付いていない状態になっています。nanoで新しく作ったファイルは、初期状態では「読み書きはできるが実行はできない」普通のテキストファイルとして扱われるためです。

POINT

シバン#!/bin/bash#は、シェルスクリプトの世界では本来コメント(説明書き。実行時に無視される行)の印です。ただし1行目の#!だけは特別扱いされ、コメントではなく「実行するプログラムの指定」として読まれます。

ゆみちゃん
ゆみ

シバンを書き忘れても動いちゃう場合はあるんだけど、環境によって解釈のされ方が変わって事故ることがあるから、「1行目には絶対#!/bin/bash」を癖にしておくのがおすすめだよ! おまじないだと思って毎回書いちゃおう!

SET 2 ― 実行権限を与えて動かす

ubuntu@lightsail: ~/scripts
  1. $./hello.sh
  2. bash: ./hello.sh: Permission denied
  3. $bash hello.sh
  4. Hello, Linux Drill!
  5. $sh hello.sh
  6. Hello, Linux Drill!
  7. $chmod +x hello.sh
  8. $ls -l hello.sh
  9. $./hello.sh
  10. Hello, Linux Drill!
  11. 今のユーザーは ubuntu です
  12. $/home/ubuntu/scripts/hello.sh
  13. $cd ~
  14. $~/scripts/hello.sh
  15. $cd ~/scripts
解説 ― SET 2 で何をしたか

1行目、./hello.shのように./(第1章1-1で学んだ「今ここ」を指す相対パス)を付けてファイルを直接実行しようとすると、出力例のとおりPermission denied(権限がありません)というエラーになります。これがSET 1で確認した「実行権限が付いていない」状態の結果です。

2行目のbash hello.sh3行目のsh hello.shは、どちらも実行権限のないファイルでも動かせる方法です。bashshというプログラムに、引数として「このファイルの中身を読んで実行して」と直接お願いしている形なので、ファイル自体に実行権限が無くても動きます。ただしこれはあくまで一時しのぎの方法で、スクリプトを1つの独立したコマンドとして育てていくには、次のchmodによる本来のやり方を覚える必要があります。

4行目のchmod +x hello.sh(第2章2-4で学習済み)で、ファイルに実行権限(x)を追加します。5行目のls -lで確認すると、権限表示にxの文字が増えているはずです。6行目で改めて./hello.shを実行すると、今度はエラーにならず、出力例のとおりスクリプトの中身が上から順に実行されます。

7行目の/home/ubuntu/scripts/hello.shのように、絶対パスを直接指定して実行することもできます。8行目でホームディレクトリへ移動しても、9行目のように~/scripts/hello.shと書けば場所を問わず実行できることが確認できます。実行権限さえ付いていれば、./付きの相対パスでも絶対パスでも、パスを明示すればどこからでも動かせるのがシェルスクリプトの基本的な性質です(ただし6-1で学んだ$PATHに登録されたディレクトリでない限り、ファイル名だけで呼び出すことはできません)。最後に10行目で~/scriptsへ戻り、次のSETへ進みます。

ゆみちゃん
ゆみ

「せっかく書いたのにPermission denied!」ってなるの、シェルスクリプト初心者が100%通る道だから安心して! chmod +xを打つだけで解決するから、エラーを見たら「あ、実行権限忘れてた」ってすぐ思い出せるようになるよ。

SET 3 ― readでキーボード入力を受け取る

ubuntu@lightsail: ~/scripts
  1. $nano greet.sh
  2. (#!/bin/bash から始まる下のスクリプトを入力し保存)
  3. $cat greet.sh
  4. #!/bin/bash
  5. echo "名前を入力してください:"
  6. read NAME
  7. echo "こんにちは、${NAME}さん!"
  8. echo "入力された文字数は${#NAME}文字です"
  9. $chmod +x greet.sh
  10. $./greet.sh
  11. 名前を入力してください:
  12. yumi
  13. こんにちは、yumiさん!
  14. 入力された文字数は4文字です
  15. $./greet.sh
  16. 名前を入力してください:
  17. devteam
  18. こんにちは、devteamさん!
  19. 入力された文字数は7文字です
  20. $ls -l
  21. $wc -l greet.sh
  22. 5 greet.sh
  23. $which greet.sh
  24. $./greet.sh < /dev/null
  25. 名前を入力してください:
  26. $cd ~
解説 ― SET 3 で何をしたか

1行目で新しいスクリプトgreet.shを書きます。中身の3行目read NAMEが今回の主役です。readはキーボードからの入力を待ち受け、入力された文字列を指定した変数(ここではNAME)に入れてくれるコマンドです。2行目のechoで先に「何を入力すればいいか」を案内しておくのが親切なスクリプトの基本形です。

4行目のecho "こんにちは、${NAME}さん!"では、$NAMEではなく${NAME}のように波かっこで囲んでいます。これは変数名のすぐ後ろに別の文字(ここでは「さん」)を続けて書きたいときに、変数名の範囲をはっきりさせるための書き方です。$NAMEさんと書くと「NAMEさん」という1つの変数名だと誤解されてしまうため、地の文とくっつける場合は${}で囲む癖をつけておくと安全です。5行目の${#NAME}#を変数名の前に付けることで、中身の文字数を数えられる書き方で、余裕があれば覚えておくと便利な小技です。

3行目のchmod +x greet.shで実行権限を与え、4行目の./greet.shで実行します。出力例のとおり、案内文が表示された後にカーソルが入力待ちの状態になるので、yumiと打ってEnterを押すと、readがそれを受け取ってNAMEに格納し、挨拶と文字数が表示されます。5行目でもう一度devteamという名前で実行し、渡す値が変わればスクリプトの出力も自動で変わることを確認します。

6行目のls -lで、hello.shgreet.shの両方に実行権限(x)が付いていることを確認します。7行目のwc -lで行数を確認すると、出力例のとおり5行(シバン込み)であることがわかります。8行目のwhich greet.shは、6-1で学んだ$PATH~/scriptsが含まれていないため、何も表示されずに終わります。./greet.shのようにパスを付ければ実行できても、名前だけでは呼び出せないことがこの一手で確認できます。

9行目の./greet.sh < /dev/nullは、第3章3-3で学んだリダイレクト<を使い、/dev/null(何も中身が無い特殊なファイル)を入力として渡す小技です。readは空の入力を受け取ってすぐに処理を続けるため、キーボードで何も打たなくてもエラーにならずに1回分の流れを確認できます。この2本のスクリプトは~/scriptsに残したまま、10行目のcd ~でホームディレクトリへ戻り、このページを終えます。次のページからは、条件によって処理を分けたり、同じ処理を繰り返したりする、もっと実用的なスクリプトに挑戦します。

まとめ

6-2では、~/scriptsという作業場を作り、シバン・実行権限・readを使った最初のシェルスクリプトを2本書きました。このページで叩けるようになったコマンドを一覧にまとめます。

コマンド / 記法何をするか覚え方
#!/bin/bashスクリプトの1行目に書き、実行するシェルを宣言する(シバン)おまじないとして必ず1行目に書く
chmod +x ファイル名ファイルに実行権限を付与するx = eXecute(実行)
./ファイル名実行権限のあるスクリプトを実行する./ = 今ここにあるこのファイル
bash ファイル名実行権限が無くてもbashに読み込ませて実行するbashに直接お願いする方法
read 変数名キーボード入力を受け取り変数に格納する入力を「読み込む」
${変数名}変数名の範囲を明示して展開する地の文とくっつくときは波かっこ

次のページ「6-3. 条件分岐と繰り返し」では、ifによる条件分岐とforwhileによる繰り返しを使い、状況に応じて動きを変えるスクリプトを書いていきます。

脚注 ─ 用語解説
  1. シェルスクリプト … 複数のコマンドを順番に並べて1つのファイルにまとめ、名前を指定するだけでまとめて実行できるようにしたファイル。
  2. シバン … スクリプトファイルの1行目に書く#!で始まる特別な行。このファイルをどのプログラムに読み込ませて実行するかを指定する。