zsh login init 和手動採購配置文件腳本之間的不同行為是什麼?
我想在 ZSH 登錄時向 precmd_functions 添加一個函式並避免重複。由於 /etc/zprofile 獲取 /etc/profile,然後獲取 /etc/profile.d/ 下的所有 *.sh 腳本,我的解決方案是將初始化腳本添加到 /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...
在行中報告。那麼為什麼只有 login init 報告這個錯誤,而手動 source 腳本不呢?
下的文件
/etc/profile.d
預計將以 sh 語法編寫,因此推測該/etc/zprofile
源中的程式碼/etc/profile.d/*
安排以 sh 或 ash 仿真模式執行此操作,可能類似於emulate ksh -c '. /etc/profile'
.sh 和 zsh 語法之間的區別之一是它在 zsh 中
$foo[bar]
被解析為數組變數取消引用,但在 sh(以及兼容的 shell,如 bash 和 zsh)中,它是一個字元串變數,後跟一個單字元 glob(所以在 sh 中touch somefilename1 somefilename2 somefilename3; var=somefilename; echo $var[12]
列印somefilename1 somefilename2
/bash/ksh,但e
在 zsh 中)。當 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 …
函式之外:它不是源腳本的本地。)