1. uasi

    Posted

    uasi
Changes in title
+変数展開時の単語分割(word split)をマスターする
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,134 @@
+シェルスクリプトは、スペース区切りの文字列が代入された変数を展開するとき、文字列をスペースの位置で分割して複数の文字列のように扱う。この挙動は Bash (をはじめとする Bourne shell 系のシェル)と Zsh とで異なってくる。
+
+# 普通の変数について
+
+Bash では、展開する変数をクォートしなければ単語分割が起きる。クォートすれば単語分割は起きず、スペースを含む1つの文字列として展開される。 Zsh では、変数をクォートするかしないかにかかわらず単語分割は起きない。ただし、 `SH_WORD_SPLIT` オプションをオンにすると Bash 準拠の挙動に変わる(デフォルトでオフ)。以下に単語分割の例を示す:
+
+```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
+
+vor 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
+
+vor v in "$var"; do
+ echo $v
+done
+# => a b c
+```
+
+Zsh で変数を強制的に単語分割するには、パラメータ展開フラグ `z` を使って `${(z)var}` のように書く。パラメータ展開フラグの詳細ついては [`man zshexpn`](http://linux.die.net/man/1/zshexpn) の "Parameter Expansion" か [ZshWiki](http://zshwiki.org/home/scripting/paramflags) を参照のこと。
+
+# 特殊変数 `$*` と `$@` について
+
+シェルスクリプトへのコマンドライン引数を格納する特殊変数 `$*` と `$@` は、クォートされている場合の単語分割の挙動が異なる。 `"$*"` は、単語分割が起きずに1つの文字列として展開される。 `"$@"` は、引数に**クォートされていないスペース**が含まれる場合、そこで単語分割が起きる。
+
+`$*` または `$@` がクォートされていない場合、 Bash はスペースの位置で単語分割する。 Zsh はクォートされていないスペースの位置で単語分割する。
+
+以下に例を示す:
+
+```bash:wordsplit.sh
+### クォートしたスペースを含む引数を与えて実行してみる
+
+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 がオフ)の場合
+setopt no_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
+```