Zsh

zsh-為什麼我的腳本沒有讀取我的選項設置?

  • August 31, 2022

使用 zsh 5.8.1 (x86_64-apple-darwin21.0),我有一個依賴zsh 預設的基於 1 的數組索引的腳本,我想確保任何以前的使用者設置都不會干擾它。最好的做法似乎是儲存使用者的目前KSH_ARRAYS設置,然後取消設置此選項,然後在完成後將選項重置為其原始設置。我有以下內容:

#!/usr/bin/env zsh

if [[ -o ksharrays ]]; then
 echo "setting ksharrays_is_set to 1...";
 ksharrays_is_set=1;
else
 echo "setting ksharrays_is_set to 0...";
 ksharrays_is_set=0;
fi

unsetopt KSH_ARRAYS;

# here is where my script runs

if [[ ksharrays_is_set -eq 1 ]]; then
 echo "setting the ksharrays option...";
 setopt ksharrays;
fi

為了測試這一點,我setopt ksharrays在終端中執行,然後是我的腳本。但是,我仍然看到setting ksharrays_is_set to 0...終端回顯。

當我添加setopt ksharrays到第 2 行(直接在 shebang 下方)時,我看到setting ksharrays_is_set to 1...setting the ksharrays option...符合預期。

為什麼當我在終端中設置它時沒有選擇該選項,但是當我在腳本中設置它時?

編輯:我還嘗試將這些文件添加setopt ksharrays到 my~/.zshrc和ing 中,~/.zshenv然後source執行上述腳本。這也導致setting ksharrays_is_set to 0...了輸出,而不是預期的輸出。我通過在終端中執行不帶參數的命令來確認該setopt命令生效:

$ setopt

combiningchars
interactive
ksharrays
login
monitor
promptsubst
shinstdin
zle

編輯 2:我添加echo $(setopt)到腳本的頂部。唯一列印出來的是nohashdirs. 當我直接在終端中執行沒有 args時,我看不到combiningchars,interactive或任何其他選項。setopt

當你從另一個程序執行一個程序時,每個程序都是它自己的東西。僅僅因為您從 zsh 執行 zsh 並不會使第二個 zsh 以某種方式從其父級繼承某些設置。

您已經編寫了一個 zsh 腳本。因此,當您執行 時/path/to/your/script,作業系統會看到該文件以shebang行開頭並zsh從命令搜尋路徑執行。它不關心誰開始了這個過程。zsh 的新實例以預設設置開始。任何設置更改(例如 zsh 選項)都必須來自某個地方,例如命令行或配置文件或腳本的內容。

當一個程序呼叫另一個程序時,會繼承某些設置,但它們是適用於所有程序的設置,而不僅僅是適用於 zsh。主要是環境變數是繼承的。Zsh 不會根據環境變數設置選項。

如果您使用zsh中的.orsource內置函式,情況將完全不同。這將指示 zsh 從文件中讀取命令,就好像它們已寫入包含該.命令的文件中一樣。不幸的是,沒有完善的術語來區分這兩種情況:兩者都稱為“腳本”。可以執行腳本(/path/to/script從任何程序執行)或獲取腳本(. /path/to/script從 zsh 執行);可以以任何一種方式使用同一個文件,但大多數腳本只能以一種方式使用。您的腳本是要執行的獨立程序。

回到當 zsh 開始執行正在執行的腳本時會發生什麼:當 zsh 執行腳本時,它不會載入.zshrc(僅適用於 zsh 互動執行時),但它會載入/etc/zshenv~/.zshenv. 如果你放setopt ksh_arrays,你的腳本會選擇那個設置。放入任何setopt命令(或幾乎任何東西).zshenv都是一個糟糕的主意,會破壞腳本。

一旦你的腳本退出,沒有人關心(甚至記得)它啟用了哪些 zsh 選項。因此,如果您想啟用ksh_arrays腳本中的所有程式碼,只需在setopt ksh_arrays腳本開頭附近執行,故事結尾。

如果只有部分程式碼需要某些選項,請將該部分放入函式中並在函式中設置local_options選項。例如,要ksh_arrays在函式執行時啟用並在函式退出時恢復預設設置,請將其放在setopt local_options ksh_array函式頂部附近。此外,如果某些其他選項從預設值更改,則需要更改某些選項的程式碼通常也會中斷。因此,當 zsh 程式碼需要在選項可能已更改預設值的上下文中執行時,將該程式碼放在一個函式中並emulate -LR zsh在該函式中執行。這使得函式使用預設選項執行,也local_options啟用了,因此當函式退出時,對選項的任何更改都將被撤消。一些程式碼應該遵循某些“最終使用者”選項,例如mark_dirs;對於這樣的程式碼,使用emulate -L zsh(即刪除-R)選項。例如,這對於完成功能是正確的。

引用自:https://unix.stackexchange.com/questions/715638