はじめに
ロボットのウェイターを想像してください。Static なロボットは、誰に対しても「Hello, Sir」としか言えません。一方、Dynamic なロボットは相手の名前を尋ね、「Hello, Sarah」や「Hello, Mike」と言えます。
前の実験では、スクリプトは毎回まったく同じ処理を行いました。この実験では、スクリプトの外部からデータを受け取れるようにして、スクリプトを動的にします。
これはプログラミングにおける大きな転換点です。スクリプトが入力を受け取れるようになると、固定されたデモではなく、再利用できるツールになります。
ここでは、スクリプトとやり取りする 2 つの方法を学びます。
- 尋ねて聞く:スクリプトが一時停止して質問し、ユーザーの入力を待ちます(
readを使用)。 - メモを渡す:スクリプトの起動時に、スクリプトへメモを渡します(引数を使用)。
この実験を終えるころには、「World」だけでなく、任意の相手にあいさつできるコードを作れるようになります。
対話形式の入力に read を使う
最初の方法は、「会話」形式です。スクリプトに質問を表示させ、その後で回答を待つようにします。
ここでは read コマンドを使います。read は、「いったんすべてを止め、耳を傾け、ユーザーが何か入力するまで待つ」コマンドだと考えてください。
これは、実行中のスクリプトがデータを受け取る最初の例です。シェルスクリプトでは、変数はデータを一時的に保存するための名前付きの場所です。たとえば、ユーザー名、ファイル名、数値などを保存できます。変数を使うと、ハードコードされたテキストではなく変化する入力を使って処理できるため、スクリプトを再利用しやすくなります。
まず、プロジェクトのワークスペースに移動します。
cd ~/project
nano を使って、hello.sh という新しいファイルを作成します。
nano hello.sh
次のコードを入力します。
注:ユーザーの回答を保存するために、name という「箱」(変数)を定義しています。
#!/bin/bash
echo "What is your name?"
read name
echo "Hello, $name!"
コードを分解して確認しましょう。
echo "...":スクリプトが画面にメッセージを表示します。read name:スクリプトが入力を待ちます。入力した内容はnameという箱の中に保存されます。$name:スクリプトが箱を開きます。$記号は、変数の中身を取り出すための鍵です。
name と $name の違いに注目してください。name は、変数を作成したり値を代入したりするときに使う変数の名前です。$name は、「変数に保存されている値で置き換える」という意味です。この置き換えは 展開(expansion) と呼ばれ、シェルの最も重要な動作の 1 つです。
作業を保存し(Ctrl+O、Enter)、終了します(Ctrl+X)。
対話形式のスクリプトを実行する
スクリプトと会話する前に、スクリプトを実行できるように許可する必要があります。前の実験で学んだ「鍵」を覚えていますか。
実行権限を付与します。
chmod +x hello.sh
それでは、スクリプトと会話してみましょう。スクリプトを実行します。
./hello.sh
スクリプトは「What is your name?」と尋ね、その後で一時停止します。スクリプトは入力を待っています。カーソルが点滅することがあります。
名前(例:Alice)を入力し、Enter キーを押します。
What is your name?
Alice
Hello, Alice!
これは 対話形式の入力(Interactive Input) と呼ばれます。人が操作するツールには適していますが、自動化には向いていません。たとえば、このスクリプトを午前 3 時に自動実行するとします。決して返ってこない回答を待ち続けるため、処理が止まってしまいます。
この違いは、実際の運用作業で重要です。対話形式のスクリプトは人がその場にいるときは便利ですが、スケジュールされたジョブ、CI パイプライン、起動時に実行するスクリプトでは、通常、ユーザーが操作しなくても実行できる非対話形式の入力が必要です。
非対話形式の入力に引数を使う
スクリプトを自動化に対応させるには、スクリプトの実行開始前にデータを渡す方法が必要です。そうすれば、スクリプトが一時停止することはありません。これには引数(Arguments)を使います。
引数は、ドアにある「郵便受け」のようなものだと考えてください。通り過ぎるときに、そこへメッセージを入れます。
Bash では、この郵便受けに番号付きの名前が付いています。
$1は、スクリプト名の後に入力する最初の単語です。$2は 2 番目の単語です。以降も同様です。
このような番号付きの値を 位置パラメーター(positional parameters) と呼びます。位置パラメーターは、スクリプトの起動時にシェルによって自動的に作成されます。$1 を自分で定義する必要はありません。Bash が、スクリプトを起動したコマンドラインから値を設定します。
hello.sh を変更し、質問する代わりに最初の郵便受けである $1 を参照するようにします。
ファイルを開きます。
nano hello.sh
コードを次のように変更します。
#!/bin/bash
name=$1
echo "Hello, $name!"
ここで name=$1 は、$1 の郵便受けに入っている値を取り出し、name という箱に入れます。一時停止も質問もありません。
保存して終了します。
引数を指定してスクリプトを実行する
ここでは、これまでとは異なる方法でスクリプトを実行します。スクリプトの起動時に、名前をスクリプトへ直接「投げ渡し」ます。
次のコマンドを実行します。
./hello.sh LabEx
ここで LabEx が引数です。スクリプトはこの値を $1 として受け取り、すぐに次のように表示します。
Hello, LabEx!
別の名前でも試してみましょう。
./hello.sh World
すぐに実行されます。待ち時間はありません。
空の郵便受けの問題
引数を指定しなかった場合はどうなるでしょうか。
./hello.sh
次の結果になります。
Hello, !
$1 の郵便受けが空だったため、name の箱も空になっています。後の実験では、この状態を検出してエラーメッセージを表示する方法を学びます。今のところは、簡潔で自動化に対応したスクリプトを作成できました。
対話形式の入力とコマンドライン引数の違いは、基本的な重要事項です。read は実行中に入力を尋ねますが、$1 は最初から利用できます。多くの Unix ツールが引数を中心に設計されているのは、引数のほうが自動化、ドキュメント化、繰り返し実行、他のコマンドとの組み合わせを行いやすいためです。
まとめ
おめでとうございます。入力を受け取る方法を学びました。
この実験では、次の内容を確認しました。
- 対話形式モード:
readを使ってユーザーと会話しながら入力を受け取る方法(人が操作する場合に適しています)。 - 引数モード:
$1を使って、起動時にデータを受け取る方法(ロボットや自動化に適しています)。
また、$name のような変数は、スクリプトが情報を保存するための名前付きの箱にすぎないことも学びました。この考え方は、あらゆるプログラミングの基礎になります。



