シェルスクリプトは、スペース区切りの文字列が代入された変数を展開するとき、文字列をスペースの位置で分割して複数の文字列のように扱う。この挙動は Bash (をはじめとする Bourne shell 系のシェル)と Zsh とで異なってくる。
普通の変数について
Bash では、展開する変数をクォートしなければ単語分割が起きる。クォートすれば単語分割は起きず、スペースを含む1つの文字列として展開される。 Zsh では、変数をクォートするかしないかにかかわらず単語分割は起きない。ただし、 SH_WORD_SPLIT
オプションをオンにすると Bash 準拠の挙動に変わる(デフォルトでオフ)。以下に単語分割の例を示す:
### 下準備
# 第1引数を echo する関数
function echo_first {
echo $1
}
# スペース区切りの文字列を含む変数
var="a b c"
### Bash の場合
echo_first $var # => a
echo_first "$var" # => a b c
for v in $var; do
echo $v
done
# => a
# => b
# => c
for v in "$var"; do
echo $v
done
# => a b c
### Zsh (SH_WORD_SPLIT がオフ)の場合
echo_first $var # => a b c
echo_first "$var" # => a b c
for v in $var; do
echo $v
done
# => a b c
for v in "$var"; do
echo $v
done
# => a b c
Zsh で変数を強制的に単語分割するには ${=var}
のように書く。記法の詳細ついては man zshexpn
の "Parameter Expansion" を参照のこと。
特殊変数 $*
と $@
について
シェルスクリプトへのコマンドライン引数を格納する特殊変数 $*
と $@
は、それ自体がクォートされている場合の単語分割の挙動が異なる。 "$*"
は、単語分割が起きずに1つの文字列として展開される。 "$@"
は、引数に クォートされていないスペース が含まれる場合、そこで単語分割が起きる。
$*
または $@
がクォートされていない場合、 Bash はスペースの位置で単語分割する。 Zsh はクォートされていないスペースの位置で単語分割する。
以下に例を示す:
### クォートされたスペースを含む引数を与えて実行してみる
bash wordsplit.sh "a b" c
zsh wordsplit.sh "a b" c
### Bash の場合
# $*: スペースで分割
for v in $*; do
echo $v
done
# => a
# => b
# => c
# "$*": 分割なし
for v in "$*"; do
echo $v
done
# => a b c
# $@: スペースで分割
for v in $@; do
echo $v
done
# => a
# => b
# => c
# "$@": クォートされていないスペースで分割
for v in "$@"; do
echo $v
done
# => a b
# => c
### Zsh (SH_WORD_SPLIT がオフ)の場合
# $*: クォートされていないスペースで分割
for v in $*; do
echo $v
done
# => a b
# => c
# "$*": 分割なし
for v in "$*"; do
echo $v
done
# => a b c
# $@: クォートされていないスペースで分割
for v in $@; do
echo $v
done
# => a b c
# "$@": クォートされていないスペースで分割
for v in "$@"; do
echo $v
done
# => a b
# => c