Shell の特殊変数

ShellBeginner

はじめに

この実験では、シェルスクリプトにおける特殊変数(Special Variables)について学びます。これらの変数は、コマンドライン引数、スクリプト名、プロセス ID など、スクリプトの実行環境に関する重要な情報を提供します。これらの変数を理解することで、より柔軟で強力なシェルスクリプトを作成できるようになります。

最初のスクリプトの作成

まずは、特殊変数の使い方を確認するためのシンプルなシェルスクリプトを作成しましょう。

  1. WebIDE のターミナルを開きます。入力待ちのコマンドプロンプトが表示されているはずです。

  2. プロジェクトディレクトリに移動します。

cd ~/project

このコマンドは、現在のディレクトリをこの実験のデフォルト作業ディレクトリである ~/project に変更します。

  1. 次のコマンドを使用して、special_vars.sh という名前の新しいファイルを作成します。
touch special_vars.sh

touch コマンドは、ファイルが存在しない場合は空のファイルを作成し、存在する場合はタイムスタンプを更新します。

  1. WebIDE のエディタでファイルを開きます。画面左側のファイルエクスプローラーでファイル名をクリックすると開くことができます。

  2. ファイルに以下の内容を記述します。

#!/bin/bash

echo "Script Name: $0"
echo "First Argument: $1"
echo "Second Argument: $2"
echo "All Arguments: $@"
echo "Number of Arguments: $#"
echo "Process ID: $$"

各行の役割を解説します。

  • #!/bin/bash: シバン(Shebang)と呼ばれます。このスクリプトを解釈するために bash を使用することをシステムに伝えます。
  • $0: この特殊変数にはスクリプトの名前が格納されます。
  • $1$2: それぞれ、1 番目と 2 番目のコマンドライン引数を表します。
  • $@: スクリプトに渡されたすべてのコマンドライン引数を表します。
  • $#: コマンドライン引数の個数を示します。
  • $$: 現在実行されているシェルのプロセス ID(PID)を示します。
  1. 内容を入力したらファイルを保存します。

  2. ターミナルで次のコマンドを実行し、スクリプトに実行権限を付与します。

chmod +x special_vars.sh

chmod コマンドはファイルの権限を変更します。+x オプションは実行権限を追加するもので、これによりスクリプトを直接実行できるようになります。

引数を指定してスクリプトを実行する

スクリプトが作成できたので、異なる引数を指定して実行し、特殊変数がどのように変化するかを確認してみましょう。

  1. 引数を指定せずにスクリプトを実行します。
./special_vars.sh

スクリプト名の前にある ./ は、現在のディレクトリにあるスクリプトを探すようシェルに指示するものです。

以下のような出力が表示されるはずです。

Script Name: ./special_vars.sh
First Argument:
Second Argument:
All Arguments:
Number of Arguments: 0
Process ID: 1234

引数を指定していないため、1 番目と 2 番目の引数は空になり、引数の数は 0 になっていることに注目してください。

  1. 次に、いくつかの引数を指定して実行してみます。
./special_vars.sh hello world

出力は以下のようになります。

Script Name: ./special_vars.sh
First Argument: hello
Second Argument: world
All Arguments: hello world
Number of Arguments: 2
Process ID: 1235

変化した点は以下の通りです。

  • $1 に "hello" が格納された
  • $2 に "world" が格納された
  • $@ にすべての引数 "hello world" が表示された
  • $# が引数の数である 2 を示した

プロセス ID($$)は、実行のたびにオペレーティングシステムによって割り当てられるため、実行ごとに異なる値になります。

$?$! の理解

他にも重要な特殊変数として $?$! があります。これらを確認するための新しいスクリプトを作成しましょう。

  1. exit_status.sh という名前の新しいファイルを作成します。
touch ~/project/exit_status.sh
  1. エディタでファイルを開き、以下の内容を記述します。
#!/bin/bash

echo "Running a successful command:"
ls /home
echo "Exit status: $?"

echo "Running a command that will fail:"
ls /nonexistent_directory
echo "Exit status: $?"

echo "Running a background process:"
sleep 2 &
echo "Process ID of last background command: $!"

このスクリプトの解説:

  • $?: 最後に実行されたコマンドの終了ステータス(Exit Status)を返します。通常、0 は成功を意味し、それ以外の値はエラーが発生したことを示します。
  • $!: 最後にバックグラウンドで実行されたコマンドのプロセス ID を返します。
  • コマンドの末尾に & を付けると、そのコマンドをバックグラウンドで実行します。
  1. ファイルを保存し、実行権限を付与します。
chmod +x ~/project/exit_status.sh
  1. スクリプトを実行します。
./exit_status.sh

以下のような出力が表示されるはずです。

Running a successful command:
labex
Exit status: 0
Running a command that will fail:
ls: cannot access '/nonexistent_directory': No such file or directory
Exit status: 2
Running a background process:
Process ID of last background command: 1236

注目ポイント:

  • 最初の ls コマンドは成功したため、$?0 になります。
  • 2 番目の ls コマンドは(ディレクトリが存在しないため)失敗し、$?2(エラーを示す 0 以外の値)になります。
  • sleep コマンドがバックグラウンドで実行され、$! によってそのプロセス ID が表示されます。

関数内での特殊変数の使用

特殊変数は関数の中でも使用できます。これを確認するスクリプトを作成しましょう。

  1. function_vars.sh という名前の新しいファイルを作成します。
touch ~/project/function_vars.sh
  1. エディタでファイルを開き、以下の内容を記述します。
#!/bin/bash

function print_args {
  echo "Function Name: $0"
  echo "First Argument: $1"
  echo "Second Argument: $2"
  echo "All Arguments: $@"
  echo "Number of Arguments: $#"
}

echo "Calling function with two arguments:"
print_args hello world

echo "Calling function with four arguments:"
print_args one two three four

このスクリプトでは、特殊変数を使用する print_args という関数を定義しています。その後、異なる数の引数を渡してこの関数を 2 回呼び出しています。

  1. ファイルを保存し、実行権限を付与します。
chmod +x ~/project/function_vars.sh
  1. スクリプトを実行します。
./function_vars.sh

以下のような出力が表示されるはずです。

Calling function with two arguments:
Function Name: ./function_vars.sh
First Argument: hello
Second Argument: world
All Arguments: hello world
Number of Arguments: 2
Calling function with four arguments:
Function Name: ./function_vars.sh
First Argument: one
Second Argument: two
All Arguments: one two three four
Number of Arguments: 4

注目ポイント:

  • $0 は関数名ではなく、依然としてスクリプト名を指します。
  • $1$2$@$# は、スクリプトの引数と同じように、関数の引数に対して機能します。
  • これらの変数の値は、関数が呼び出されるたびに、渡された引数に応じて変化します。

$@$* の違いを理解する

特殊変数 $@$* はどちらもすべてのコマンドライン引数を表しますが、ダブルクォーテーションで囲んだ場合の挙動が異なります。この違いを確認しましょう。

  1. at_vs_star.sh という名前の新しいファイルを作成します。
touch ~/project/at_vs_star.sh
  1. エディタでファイルを開き、以下の内容を記述します。
#!/bin/bash

echo "Using \$@:"
for arg in "$@"; do
  echo "Argument: $arg"
done

echo "Using \$*:"
for arg in "$*"; do
  echo "Argument: $arg"
done

このスクリプトは、ループ内での "$@""$*" の挙動の違いを示します。

  1. ファイルを保存し、実行権限を付与します。
chmod +x ~/project/at_vs_star.sh
  1. スペースを含む引数など、複数の引数を指定してスクリプトを実行します。
./at_vs_star.sh "arg with spaces" another_arg "third arg"

以下のような出力が表示されるはずです。

Using $@:
Argument: arg with spaces
Argument: another_arg
Argument: third arg
Using $*:
Argument: arg with spaces another_arg third arg

何が起きているのか:

  • "$@" を使用すると、各引数は個別の要素として扱われます。スペースを含む引数も、一つの単位として正しく保持されます。
  • "$*" を使用すると、すべての引数が一つの文字列に結合されます。各引数は IFS(内部フィールド区切り文字)変数の最初の文字(通常はスペース)で区切られます。

この違いは、スペースや特殊文字を含む可能性のある引数を処理する場合に非常に重要になります。

まとめ

この実験では、シェルスクリプトにおける特殊変数とその効果的な活用方法について学びました。$0$1$@$#$$$?$! といった様々な特殊変数を使用するスクリプトを作成しました。また、関数内での挙動や、コマンドライン引数を処理する際のコンテキストによる違いについても確認しました。

学んだポイント:

  1. $0$1$2 などは、スクリプト名やコマンドライン引数を表します。
  2. $@$# を使うと、すべての引数を操作したり、その数を数えたりできます。
  3. $$ は現在のプロセス ID を取得でき、一意のテンポラリファイルを作成する際などに役立ちます。
  4. $? は直前のコマンドが成功したかどうかを確認するのに役立ちます。
  5. $! は最後に実行したバックグラウンドプロセスの PID を取得でき、ジョブ制御に利用できます。
  6. "$@""$*" はクォート時の挙動が異なり、スペースを含む引数を扱う際に重要です。

これらの特殊変数を理解することは、より高度で柔軟なシェルスクリプトを書くために不可欠です。これらを利用することで、入力に応じて動作を変えたり、実行環境に関する貴重な情報を取得したりするスクリプトを作成できるようになります。

今後もシェルスクリプトの練習を続け、これらの特殊変数を活用してみてください。より詳細な情報が必要な場合は、bash のマニュアル(man bash)を参照することをお勧めします。