bashとzshで変数内のスペースの分割処理が違うことを知った話

タイトル通りなのですが、bashとzshで変数にスペースが入っている場合に処理が違うことを知らなかったためにハマりました。

以下
zshとbashでは変数の単語の分割ルールが違う
https://qiita.com/mollifier/items/7fdbf15765ccf37f4881
に記載されていることをなぞっているだけの内容ですが、一応自分でもテストしてみます。Windows10+WSL(Ubuntu)です。

変数tmp_argsに"-l -a"を代入、それを引数としてlsするスクリプトを書きます。

まずはbashの場合(shでも同様に動きます)。

#!/bin/bash
echo -e '\nbash'

echo -e '\n[1] ls -l -a(動く)'
ls -l -a

echo -e  '\n変数 tmp_args="-l -a" 宣言'
tmp_args="-l -a"

echo -e  '\n[2] ls ${tmp_args}(動く、bashなら変数が展開される)'
ls ${tmp_args}

echo  -e '\n[3] ls "${tmp_args}"(動かない、クォーテーションで囲うと展開されない)'
ls "${tmp_args}"

引数の変数をそのまま使用した場合

echo -e  '\n[2] ls ${tmp_args}(動く、bashなら変数が展開される)'
ls ${tmp_args}

bashだと引数が分割されて正常に動きます。

引数の変数をクォーテーションで囲んだ場合

echo  -e '\n[3] ls "${tmp_args}"(動かない、クォーテーションで囲うと展開されない)'
ls "${tmp_args}"

引数が分割されないためエラーになります。


次はzshの場合。

#!/usr/bin/env zsh

echo -e '\nzsh'

echo -e '\n[1] ls -l -a(動く)'
ls -l -a

echo -e '\n変数 tmp_args="-l -a" 宣言'
tmp_args="-l -a"

echo -e '\n[2] ls ${tmp_args}(動かない、bashなら変数が展開されるがzshでは展開されない)'
ls ${tmp_args}

echo -e '\n[3] ls "${tmp_args}"(動かない、クォーテーションで囲うと展開されない)'
ls "${tmp_args}"

echo -e '\n[4] ls ${=tmp_args}(動く、この書き方だと展開される)'
ls ${=tmp_args}

echo -e '\n[5] setopt SH_WORD_SPLIT後にls ${tmp_args}(動く、bashと同じ様に展開される)'
setopt SH_WORD_SPLIT
ls ${tmp_args}

引数の変数をそのまま使用した場合

echo -e '\n[2] ls ${tmp_args}(動かない、bashなら変数が展開されるがzshでは展開されない)'
ls ${tmp_args}

zshでは展開されないためエラーになります。


・変数を${=tmp_args}と記述(一時的にSH_WORD_SPLIT を有効化して展開)
setopt SH_WORD_SPLITを宣言(スペースの解釈をbash/sh互換にする)
で展開されて正常に動きます。

echo -e '\n[4] ls ${=tmp_args}(動く、この書き方だと展開される)'
ls ${=tmp_args}

echo -e '\n[5] setopt SH_WORD_SPLIT後にls ${tmp_args}(動く、bashと同じ様に展開される)'
setopt SH_WORD_SPLIT
ls ${tmp_args}

setoptはset optionの意味で(多分)、オプションを有効化する際に使用します。無効化はunsetopt。
様々なオプションがあるので、必要なものを.zshrcに設定すると使い勝手が上がります。

【了】

この記事が気に入ったらサポートをしてみませんか?