Zsh

在命令行上測試失敗(正確),但在腳本中成功(錯誤地)

  • March 27, 2022

為了這個問題,假設 glob/a/b/c/*不產生匹配項。

這意味著以下測試應該失敗(換句話說,它應該產生一個非零$?):

[[ -n /a/b/c/*(#qN) ]]

如果我直接在 (zsh) 命令行上執行測試,實際上就是這種情況。但是,如果我在腳本中粘貼完全相同的測試,它會成功,這不是預期的行為。

如果我使用標誌執行相同的腳本-x,則生成的跟踪將測試顯示為

[[ -n '/a/b/c/*(#qN)' ]]

我不明白為什麼單引號出現在 test 的參數周圍;在腳本的原始碼中根本沒有引號。

如果 zsh 自動插入這些單引號,這就解釋了為什麼文本會成功。

問題:

  1. 為什麼此表達式的命令行版本和腳本版本之間存在差異?
  2. 我需要做什麼才能使測試(正確)在腳本中失敗?

CONDITIONAL EXPRESSIONSzsh手冊的部分:

文件名生成不會對條件的任何形式的參數執行。但是,在正常 shell 擴展有效且選項 EXTENDED_GLOB 生效的任何情況下,都可以通過在字元串末尾使用格式為 (#q) 的顯式 glob 限定符來強制執行此操作。

換句話說,在您的腳本中,如果extendedglob未設置該選項,則將/a/b/c/*(#qN)其視為文字字元串。

檢查 glob 是否與任何文件匹配的更好的習慣用法(IMO)是:

()(($#)) /a/b/c/*(NY1)

那不需要extendedglob和那個特殊情況[[ -n ...(#qN) ]]Y1並且由於在第一場比賽中停止,效率也更高。

它通過將全域擴展傳遞給一個匿名函式來工作,該函式的主體是(($#))算術表達式,如果該匿名函式的參數數量非零,則返回 true。

您可以將其擴展到以下內容:

if ()(( $# >= 3 )) /a/b/c*(NY3); then
 echo there were at least 3 matching files.
fi

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