zsh -z は「+x」の意味をテストします。

zsh -z は「+x」の意味をテストします。

私は初めてzshに触れ、何年もの間bashユーザーでした。

例 zsh スクリプトでテストを表示できます。

if [ ! -z ${ZSH_MOTD_CUSTOM+x} ]; then

Bashでは次のことを楽しみにしています。

if [ ! -z "$ZSH_MOTD_CUSTOM" ]; then

zshの例とbashに適用されている場合は、+xの意味がわかりません。

ベストアンサー1

${var+string}Bourneシェル(1970年代後半から)とすべてのPOSIXシェル(bashを含む)と同じ演算子です。 zsh ドキュメントに対応する説明がありますinfo zsh 'Parameter Expansion'

${NAME+WORD}
${NAME:+WORD}
設定されている場合は、置き換えられるNAMEか、2 番目の形式で null でない WORD場合、置き換えられる項目はありません。

そこで見つけるのは難しいですが、info bash 'Parameter Expansion'そこでも同じです。の場合はsh確認できます。POSIX仕様(ただし、bashマニュアルのように${parameter:+word}1からコロンを省略した効果を言及した文章に注意する必要があります。)

Bashや他のBourne様シェルとの主な違いは、引用解除が分割+globの影響を受けないことです。なぜなら${ZSH_MOTD_CUSTOM+x}、zsh は、引数拡張時に IFS 分割および/またはグロービングを実行したい場合に明示的に要求する必要があるからです。$=var$~varワイルドカード(厳密には内容を$varパターンとして扱う)の$=~var場合、どちらも他のシェルと同じです$var

しかし、参照されていない拡張はまだnullで削除されるため、これは間違っています。しかし、この場合、偶然それは問題にならず、おそらく著者が機能しないの[ ! -z $expansion ]ではなく、それを書くことを選んだ理由でしょう。[ -n $expansion ]

ifが空の場合($expansionifが設定されていない場合)、notになるので、拡張子が空でないかどうかをテストしませんが、それ自体が空の文字列であるかどうかをテストする(明らかにそうではありません)、誤った結果によるエラーを実装して正しい結果を取得します(変数が設定されているかテスト)。${ZSH_MOTD_CUSTOM+x}$ZSH_MOTD_CUSTOM[ ! -z $expansion ][ ! -z ][ ! -z '' ]-z

Bashで引用されていない内容は${ZSH_MOTD_CUSTOM+x}分割+globの影響を受けているため、バグが多いが空の文字列またはリテラルにのみ拡張されるため、以下をx含む場合にのみ問題が発生します。$IFSx

$ bash -xc 'IFS=y; [ ! -z ${HOME+x} ]; echo "$?"'
+ IFS=y
+ '[' '!' -z x ']'
+ echo 0
0
$ bash -xc 'IFS=x; [ ! -z ${HOME+x} ]; echo "$?"'
+ IFS=x
+ '[' '!' -z '' ']'
+ echo 1
1
$ zsh -xc 'IFS=x; [ ! -z ${HOME+x} ]; echo "$?"'
+zsh:1> IFS=x
+zsh:1> [ ! -z x ']'
+zsh:1> echo 0
0

これすべてのPOSIXシェルの正しい構文する:

if [ -n "${ZSH_MOTD_CUSTOM+x}" ]

これはBourneシェルでも機能します。拡張は空の文字列のみが可能なため...などの[ -n "$var" ]値では失敗します(したがって、古代の実装には問題のある文字列はありません)。$var=-gtx[

zshには、変数が設定されていることを確認するより慣用的な方法があります。たとえば、次のようになります。

if (( $+ZSH_MOTD_CUSTOM ))

ifが設定されている場合$+varに展開され、そうでない場合に展開されます。1$var0

または:

if [[ -v ZSH_MOTD_CUSTOM ]]

À la ksh(bashでも見つかりました)。

とにかく[ ! -z "$ZSH_MOTD_CUSTOM" ]作成する方法自体は複雑ですが、[ -n "$ZSH_MOTD_CUSTOM" ]他のことを行います。つまり、変数が設定されているかどうかに関係なく、変数がnullでないことを確認します。最大の違いは、設定されている$ZSH_MOTD_CUSTOM場合はfalseを返しますが、nullを返すことです。バリアントとは異なり、変数が設定されておらず、${ZSH_MOTD_CUSTOM+x}オプションが有効な場合でもエラーが発生します。nounset

$ zsh -c 'if [ -n "$foo" ]; then echo non-empty; else echo empty; fi'
empty
$ foo= zsh -o nounset -c 'if [ -n "$foo" ]; then echo non-empty; else echo empty; fi'
empty
$ foo= zsh -o nounset -c 'if [ -n "${foo+x}" ]; then echo set; else echo unset; fi'
set
$ zsh -o nounset -c 'if [ -n "$foo" ]; then echo non-empty; else echo empty; fi'
zsh:1: foo: parameter not set
$ zsh -o nounset -c 'if [ -n "${foo+x}" ]; then echo set; else echo unset; fi'
unset
$ zsh -o nounset -c 'if [ -n "${foo-}" ]; then echo non-empty; else echo empty; fi'
empty

(最後は${foo-}同じものに拡張されますが、$foo(aka)効果を避けるために使用されます。)nounsetset -u


1この機能が存在するBourneシェルでは、最初は(1970年代後半のUnixバージョン7)、コロンのないバージョンのみがサポートされ、後でコロン付きのバージョンがサポートされました。システムIIIで

おすすめ記事