シェルスクリプトの基本概念
シェルは、ユーザーがオペレーティングシステムと対話するためのコマンドラインインターフェース(CLI)言語です。コマンドラインで直接命令を実行するだけでなく、一連の論理操作をファイルに記述し、シェルスクリプトとして再利用することも可能です。
一般的なLinux環境では、デフォルトのシェルとしてBash(Bourne Again Shell)が広く利用されています。このセクションでは、Bashスクリプトの基本的な構文について解説します。
シェルスクリプトの先頭には、そのスクリプトを実行するシェルインタープリタを指定する「Shebang」行を記述するのが一般的です。例えば、Bashを使用する場合は#! /bin/bashと記述します。
スクリプトの実行例
my_first_script.shという名前のファイルを作成し、以下の内容を記述します。
#! /bin/bash
echo "こんにちは、シェルスクリプトの世界へ!"
実行可能ファイルとしての実行
スクリプトに実行権限を付与し、直接実行します。
user@host:~$ chmod +x my_first_script.sh # 実行権限の付与
user@host:~$ ./my_first_script.sh # 現在のディレクトリから実行
こんにちは、シェルスクリプトの世界へ!
user@host:~$ /home/user/my_first_script.sh # 絶対パスで実行
こんにちは、シェルスクリプトの世界へ!
インタープリタを指定して実行
bashコマンドに続けてスクリプトファイルを指定して実行することもできます。
user@host:~$ bash my_first_script.sh
こんにちは、シェルスクリプトの世界へ!
コメントの記述方法
単一行コメント
行頭またはコードの途中に#を記述すると、それ以降の文字列はその行のコメントとして扱われます。
# これはコメント行です
echo 'Hello Bash' # これもコメントです
複数行コメント
複数行にわたるコメントは、:<DELIMITERは任意の文字列で構いません。
:<
変数の利用
変数の定義
シェル変数に値を割り当てる際、=の前後にはスペースを入れません。文字列はシングルクォート、ダブルクォート、またはクォートなしで定義できます。
my_name='Tarou' # シングルクォートで文字列を定義
user_greeting="Hello $my_name" # ダブルクォートで文字列を定義
app_version=1.0 # クォートなしで定義
変数の参照
変数に格納された値を参照するには、変数名の前に$を付けます。変数名が他の文字列と隣接する場合は、${変数名}の形式で境界を明示すると良いでしょう。
my_name="Jiro"
echo $my_name # "Jiro"と出力
echo ${my_name} # "Jiro"と出力
echo ${my_name}s_mac # "Jiros_mac"と出力 (変数名の境界を明確に)
読み取り専用変数
readonlyコマンドまたはdeclare -rオプションを使用して、変数を読み取り専用に設定できます。一度読み取り専用に設定された変数の値は変更できません。
SYSTEM_NAME="Linux"
readonly SYSTEM_NAME
# declare -r SYSTEM_NAME # こちらの形式でも同様
SYSTEM_NAME="Unix" # エラーが発生します
変数の削除
unsetコマンドを使うと、変数をメモリから削除できます。
temp_var="temporary value"
echo $temp_var # "temporary value"と出力
unset temp_var
echo $temp_var # 空行が出力される (変数が削除されているため)
変数のスコープ: ローカル変数と環境変数
変数はそのスコープによって分類されます。
- ローカル変数(カスタム変数): そのシェルプロセス内でのみ有効で、子プロセスには引き継がれません。
- 環境変数(グローバル変数): そのシェルプロセスとそこから起動されるすべての子プロセスでアクセス可能です。
ローカル変数を環境変数に変換するにはexportコマンドまたはdeclare -xを使用します。
user@host:~$ current_project="MyProject" # ローカル変数
user@host:~$ export current_project # 環境変数に変換
user@host:~$ declare -x ANOTHER_VAR="some_value" # こちらも環境変数に変換
環境変数をローカル変数に戻すにはdeclare +xを使用します。
user@host:~$ export GLOBAL_VAR="Global Value" # 環境変数を定義
user@host:~$ declare +x GLOBAL_VAR # ローカル変数に戻す
文字列操作
シェルスクリプトでは文字列の定義と操作が頻繁に行われます。
シングルクォートとダブルクォートの違い
- シングルクォート
'...': 内部の文字は文字通りに解釈され、変数の展開やコマンドの実行は行われません。
- ダブルクォート
"...": 内部で変数の展開($VAR)やコマンド置換($(command))が行われます。
target_user="Alice"
echo 'こんにちは、$target_userさん!' # 出力: こんにちは、$target_userさん!
echo "こんにちは、$target_userさん!" # 出力: こんにちは、Aliceさん!
文字列の長さ取得
${#変数名}の形式で文字列の長さを取得できます。
my_string="Bash Programming"
echo ${#my_string} # 出力: 16
部分文字列の抽出
${変数名:オフセット:長さ}の形式で部分文字列を抽出できます。オフセットは0から始まります。
full_path="/home/user/document/report.txt"
echo ${full_path:11:8} # 出力: document
特別な変数
Bashは、スクリプトの実行状態や引数に関する情報を格納する特別な変数をいくつか提供しています。
スクリプト引数変数
スクリプト実行時に渡されたコマンドライン引数は、$1, $2, ... の形式でアクセスできます。$0はスクリプト自身のファイル名(パスを含む)を示します。
process_args.shというスクリプトの例:
#! /bin/bash
echo "スクリプト名: $0"
echo "第1引数: $1"
echo "第2引数: $2"
echo "第3引数: $3"
実行例:
user@host:~$ chmod +x process_args.sh
user@host:~$ ./process_args.sh alpha beta gamma
スクリプト名: ./process_args.sh
第1引数: alpha
第2引数: beta
第3引数: gamma
その他の特殊変数
変数
説明
$#
スクリプトに渡された引数の総数(上記例では3)
$*
すべての引数を1つの文字列として(スペース区切りで)表現。例: "alpha beta gamma"
$@
各引数を個別の文字列として表現。ダブルクォートで囲むと、"alpha" "beta" "gamma" のように扱われる
$$
現在実行中のスクリプトのプロセスID (PID)
$?
直前に実行されたコマンドの終了ステータス。通常、0は成功、0以外はエラーを示す
$(command)
commandの標準出力結果を返す(入れ子可能)
`command`
commandの標準出力結果を返す(バッククォート。入れ子不可)
配列の利用
Bashでは、複数の値を格納できる一次元配列をサポートしています。配列のインデックスは0から始まります。
配列の定義
配列は括弧()で囲み、要素をスペースで区切って定義します。
fruit_list=(apple banana "orange juice" grape) # 複数の型を混在可能
個々の要素を直接代入して配列を定義することもできます。
colors[0]="red"
colors[1]="green"
colors[2]="blue"
配列要素の参照
特定の配列要素の値は${配列名[インデックス]}の形式で取得します。
echo ${fruit_list[0]} # 出力: apple
echo ${fruit_list[2]} # 出力: orange juice
配列全体の参照
配列のすべての要素を参照するには、${配列名[@]}または${配列名[*]}を使用します。
echo ${colors[@]} # 出力: red green blue
echo ${colors[*]} # 出力: red green blue
配列の長さ(要素数)
配列の要素数は${#配列名[@]}または${#配列名[*]}で取得できます。
echo ${#fruit_list[@]} # 出力: 4
echo ${#colors[*]} # 出力: 3
exprコマンドによる式の評価
exprコマンドは、文字列や数値の式を評価するために使用されます。結果は標準出力に出力され、終了ステータスも設定されます。
expr 式
注意点:
- 各項はスペースで区切る必要があります。
- シェルが特殊文字として解釈する文字(例:
*, <, >, (, )など)は、バックスラッシュ\でエスケープするか、クォートで囲む必要があります。
- 論理式の場合、結果が真なら
1、偽なら0を標準出力に出力し、終了ステータスは真なら0、偽なら1になります。
文字列式
length STRING: STRINGの長さを返します。
index STRING CHARSET: CHARSETに含まれる任意の文字がSTRING内で最初に出現する位置(1から始まるインデックス)を返します。見つからない場合は0。
substr STRING POSITION LENGTH: STRINGからPOSITIONの位置(1から始まる)からLENGTH文字分の部分文字列を抽出します。
target_text="Learning Bash"
echo `expr length "$target_text"` # 出力: 13
echo `expr index "$target_text" "snar"` # 出力: 6 (nが最初に出現)
echo `expr substr "$target_text" 10 4` # 出力: Bash
整数式
exprは基本的な算術演算をサポートしています。乗算記号*はエスケープが必要です。
+ -: 加算、減算
\* / %: 乗算、除算、剰余
\( \): 括弧で演算の優先順位を変更(エスケープが必要)
num_a=15
num_b=4
echo `expr $num_a + $num_b` # 出力: 19
echo `expr $num_a - $num_b` # 出力: 11
echo `expr $num_a \* $num_b` # 出力: 60 (アスタリスクはエスケープ)
echo `expr $num_a / $num_b` # 出力: 3 (整数除算)
echo `expr $num_a % $num_b` # 出力: 3
echo `expr \( $num_a + 5 \) / \( $num_b + 1 \)` # 出力: 4 ((15+5)/(4+1) = 20/5 = 4)
論理関係式
比較演算子や論理演算子も使用できます。比較演算子はエスケープが必要です。
|: 論理OR。最初の引数が非空かつ非0ならその値を返し、そうでなければ2番目の引数を返します。
&: 論理AND。両方の引数が非空かつ非0なら最初の引数を返し、そうでなければ0を返します。
< <= = == != >= >: 比較演算子。真なら1、偽なら0を返します。数値比較を優先し、失敗した場合に文字列比較を行います。
val1=8
val2=3
val3=0
echo `expr $val1 \> $val2` # 出力: 1 (val1 > val2 は真)
echo `expr $val1 '<' $val3` # 出力: 0 (val1 < val3 は偽)
echo `expr $val1 = $val2` # 出力: 0
echo `expr $val1 \<\= $val2` # 出力: 0
echo `expr $val1 \& $val2` # 出力: 8 (両方非0なので最初の値を返す)
echo `expr $val1 \& $val3` # 出力: 0 (val3が0なので0を返す)
echo `expr $val3 \| $val2` # 出力: 3 (val3が0なのでval2の値を返す)
echo `expr $val1 \| $val3` # 出力: 8 (val1が非0なのでval1の値を返す)