現場で使えるシェルスクリプト入門4 変数・クォート・パラメータ展開

シェルスクリプト IT

シェルスクリプトの変数は他言語のような厳密な型を持たず、基本的には文字列として扱われます。
ここでは変数の基本から、数値計算、bashの高度なパラメータ展開までを体系的にまとめています。

なお、環境変数や定数は大文字で表記し、ローカル変数は小文字(lower_case)にするのが一般的です。

変数の基本

変数は = で代入します。=の前後にスペースを入れるとエラーになります。

name="taro"
age="20"

ダブルクォーテーション、もしくはシングルクォーテーションで値を囲んで代入すると、値にスペースを使うことができます。

name1="yamada taro"
name2='yamashita jiro'
echo $name1 # yamada taro
echo $name2 # yamashita jiro

ダブルクォーテーションとシングルクォーテーション、どちらを使うかはケースによって異なります。以下の場合どのように表示されると思いますか?

# 苗字
familyname="yamada"

# ダブルクォーテーション
name1="name1: $familyname taro"

# シングルクォーテーション
name2='name2: $familyname jiro'

echo $name1
echo $name2

実行結果です。

name1: yamada taro
name2: $familyname jiro

ダブルクォーテーションで囲んだ方はfamilyname変数が展開されています。
一方シングルクォーテーションで囲んだ方は変数が展開されず「$familyname」とそのまま表示されています。

通常はダブルクォーテーションを使うケースが多いですが、値を厳密に扱いたいときはシングルクォーテーションで囲みます。

変数の参照

変数を参照するときは $ を付けます。

echo "$name"

${}を使うと、変数名と隣接する文字が混ざるのを防げます。
試しに以下を実行してみます。

name="taro"
echo "name1: $name_san"   # name_san という別の変数を探す
echo "name2: ${name}_san" # 正しく taro_san

${}を付けた方はname変数を正しく参照しています。

name1: 
name2: taro_san

数値計算:$(( )) を使う

変数は文字列ですが、数値計算は $(( )) で行えます。

echo $((1 + 2))   # 3

変数を使った計算も可能です。

x=10
y=3
echo $((x * y))   # 30

この場合、$(( )) 内部のxとyには$を付けなくても大丈夫です。
※ $を付けても計算できます。

高度なパラメータ展開

高度なパラメータ展開は、変数の値を加工するためのミニ言語のようなものです。 外部コマンド無しで高速に文字列処理ができるため、非常に役立ちます。

以下では体系的にパラメータ展開を分類しています。
なお、実行例では変数値と変数を見やすく区別するため、変数を大文字で記載しています。

1.デフォルト値・代入・代替

デフォルト値(値を“返す”だけ。VARに代入しない)

構文VAR値ありVAR未設定VAR空文字
${VAR:-default}VARの値defaultを返すdefaultを返す
${VAR-default}VARの値defaultを返す“”(空のまま)
NAME="" # 空文字
NAME1=${NAME:-yamada}
echo "$NAME1" # yamada
echo "$NAME" # 空文字
# NAME未設定
NAME2=${NAME-yamada}
echo "$NAME2" # yamada
echo "$NAME" # 空文字

デフォルト値を“代入”する(値を返す+VARに代入)

構文VAR値ありVAR未設定VAR空文字
${VAR:=default}VARの値defaultを代入defaultを代入
${VAR=default}VARの値defaultを代入“”(空のまま)
NAME="suzuki" # 値あり
NAME3=${NAME:=yamada} # NAME変数に値があるため代入されない
echo "$NAME3" # suzuki
echo "$NAME" # suzuki
NAME="" # 空文字
NAME3=${NAME:=yamada} # NAMEにyamadaが代入される
echo "$NAME3" # yamada
echo "$NAME" # yamada
NAME="" # 空文字
NAME4=${NAME=yamada} # NAMEは空文字
echo "$NAME4" # 空文字
echo "$NAME" # 空文字

代替(設定されているかどうかで返す値を変える)

構文VAR値ありVAR未設定VAR空文字
${VAR:+alt}alt“”(何も返さない)“”(何も返さない)
${VAR+alt}alt“”(何も返さない)alt
NAME="yamada" 
NAME5=${NAME:+morita} # NAMEが設定されているので、NAME5変数の値はmoritaに代替される
echo "$NAME5" # morita
echo "$NAME" # yamada
NAME="" # 空文字
NAME6=${NAME:+morita} # NAMEが空文字なので何も返さない
echo "$NAME6" # 空文字
echo "$NAME" # 空文字
NAME="" # 空文字
NAME6=${NAME+morita} # NAMEが空文字なので、NAME6変数の値はmoritaに代替される
echo "$NAME6" # morita
echo "$NAME" # 空文字

2.文字列の長さ

VAR="hello"
echo "${#VAR}" # 5

3.部分文字列(スライス)

VAR="abcdef"
echo "${VAR:1}"     # bcdef
echo "${VAR:1:3}"   # bcd
echo "${VAR: -2}"   # ef(「VAR:」と「-」の間にスペース必須)

4.文字列の置換

書き方動作
${VAR/pat/repl}最初の pat を repl に置換
${VAR//pat/repl}すべて置換
${VAR/#pat/repl}先頭が pat なら置換
${VAR/%pat/repl}末尾が pat なら置換
PATH="/usr/bin:/usr/local/bin"
echo "${PATH/bin/BIN}"  # /usr/BIN:/usr/local/bin
echo "${PATH//bin/BIN}"  # /usr/BIN:/usr/local/BIN
FILE="photo.jpg"
echo "${FILE/#pho/toma}"  # tomato.jpg
echo "${FILE/%.jpg/.png}"  # photo.png

以下の場合は対象文字列全体が置換されます。

VAR="abc123xyz"
echo "${VAR/*123*/FOUND}"  # FOUND

5.前方・後方の削除(パターンマッチ)

書き方動作
${VAR#pat}先頭から最短一致を削除
${VAR##pat}先頭から最長一致を削除
${VAR%pat}末尾から最短一致を削除
${VAR%%pat}末尾から最長一致を削除
FILE="/home/user/home_photo.jpg"
echo "${FILE#/*home}"   # /user/home_photo.jpg
echo "${FILE##/*home}"   # _photo.jpg
echo "${FILE##*/}"   # home_photo.jpg
echo "${FILE%home*}"    # /home/user/
echo "${FILE%%home*}"    # /
echo "${FILE%%.*}"    # /home/user/home_photo

6.変数名の展開(間接参照)

変数名を変数(間接参照)として扱います。

NAME="USER"
USER="taro"
echo "${!NAME}"   # taro

${!NAME}NAME が指す先の変数(USER)を参照するので、結果は "taro" になります。

コメント

タイトルとURLをコピーしました