zshログイン初期化と設定ファイルの手動インポートスクリプトの動作の違いは何ですか?

zshログイン初期化と設定ファイルの手動インポートスクリプトの動作の違いは何ですか?

ZSHログイン時にprecmd_functionsに機能を追加し、重複を避けたいです。 /etc/zprofileは/etc/profileをソースにし、/etc/profile.d/の下のすべての*.shスクリプトをソースにするので、私の解決策はinitスクリプトを/etc/profile.dに追加することでした。 。 Bashとの互換性を維持するために、自動ソーススクリプトnew_script.shは次のとおりです。

# zsh user
if [ -n "$ZSH_VERSION" ]; then
    source /etc/profile.d/new_script.zsh
# bash user
elif [ -n "$BASH_VERSION" ]; then
    source /etc/profile.d/new_script.bash
fi

これまではすべて緑色ですが、new_script.zshは奇妙に動作します。その内容は次のとおりです。

...    
    if (( $precmd_functions[(I)audit_hook] )); then
        hook_exist=true
    else
        hook_exist=false
    fi

zshを使用してログインして手動でインポートすると、問題なく実行されます。ただし、ログイン初期化中に自動的にインポートすると、bad output format specification行に報告されますif (( $precmd_functions...

その場合、initにログインしたときにのみこのエラーが報告され、手動インポートスクリプトでは報告されないのはなぜですか?

答え1

以下のファイルは/etc/profile.dsh構文で書かれると予想されるので、ソース/etc/zprofileのコードは/etc/profile.d/*おそらく次のshまたはashエミュレーションモードでこれを行うように配置されていますemulate ksh -c '. /etc/profile'

shとzshの構文の違いの1つは、$foo[bar]zshでは配列変数の逆参照として解析されますが、sh(およびbashやzshなどの互換シェル)では、単一文字のglobが後に続く文字列変数であることです(したがってshとしてtouch somefilename1 somefilename2 somefilename3; var=somefilename; echo $var[12]印刷されますsomefilename1 somefilename2/bash /ksh、しかしezsh に無し)。 zshがshまたはkshエミュレーションモードのとき、zsh_arrays$precmd_functions[(I)audit_hook]オプションが有効になっているため、アレイアクセスでは確認されません。precmd_functionsこの時点では空であるため(そうでなければ他のエラーが発生する可能性が高い)、算術式はになります[(I)audit_hook]。 zshのブラケット部分算術表現出力フォーマット仕様は、出力が異なる基準でフォーマットされるように指示する出力フォーマット仕様です(いくつかの異なる可能性のうち、これが出力ベースの仕様ではない理由です)。 zshが開く括弧を見ると、出力形式の仕様を解析する準備ができますが失敗します。

zsh固有のコードを作成し/etc/profile.dてzsh構文を使用する場合は、zsh構文を使用するようにzshに明示的に指示します。

if [ -n "$ZSH_VERSION" ]; then
    emulate zsh -c 'source /etc/profile.d/new_script.zsh'
fi

または、すべてのコードをnew_script.zsh関数に入れてemulate -L zsh関数の上部にあります。 (関数の外に置かないでくださいemulate -L …。ソーススクリプトにローカルではありません。)

関連情報