Zsh
在命令行上測試失敗(正確),但在腳本中成功(錯誤地)
為了這個問題,假設 glob
/a/b/c/*
不產生匹配項。這意味著以下測試應該失敗(換句話說,它應該產生一個非零
$?
):[[ -n /a/b/c/*(#qN) ]]
如果我直接在 (zsh) 命令行上執行測試,實際上就是這種情況。但是,如果我在腳本中粘貼完全相同的測試,它會成功,這不是預期的行為。
如果我使用標誌執行相同的腳本
-x
,則生成的跟踪將測試顯示為[[ -n '/a/b/c/*(#qN)' ]]
我不明白為什麼單引號出現在 test 的參數周圍;在腳本的原始碼中根本沒有引號。
如果 zsh 自動插入這些單引號,這就解釋了為什麼文本會成功。
問題:
- 為什麼此表達式的命令行版本和腳本版本之間存在差異?
- 我需要做什麼才能使測試(正確)在腳本中失敗?
從
CONDITIONAL EXPRESSIONS
zsh手冊的部分:文件名生成不會對條件的任何形式的參數執行。但是,在正常 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