Shell
zsh 擴展在非互動式腳本中的工作方式是否不同?
我目前正在研究一個非常簡單的 zsh 腳本。我經常做的是這樣的:
mv */*.{a,b} .
當我在 zsh 腳本中執行它時,它似乎以不同的方式擴展並在互動模式下工作時失敗。
% mkdir dir % touch dir/file.a % ls file.a ls: cannot access file.a: No such file or directory % mv */*.{a,b} . % ls file.a file.a
所以,這有效,但作為一個腳本:
% mkdir dir % touch dir/file.a % ls file.a ls: cannot access file.a: No such file or directory % cat script.sh #!/usr/bin/zsh mv */*.{a,b} . % ./script.sh ./script.sh:2: no matches found: */*.b
那麼,有什麼不同呢?我究竟做錯了什麼?
兩者都與
zsh
預設選項設置錯誤。您可以通過使用echo
as 命令而不是mv
.互動式地,看起來您已經
null_glob
設置了選項。根據zsh
文件,預設情況下未設置該選項。未設置該選項會發生什麼取決於是否設置了另一個選項 ,nomatch
。使用nomatch
unset (nonomatch
) 你會得到這個:% mkdir dir % touch dir/file.a % ls file.a ls: cannot access file.a: No such file or directory % echo */*.{a,b} . dir/file.a */*.b .
擴展分兩步進行。首先,
*/*.{a,b}
擴展為 2 個單詞:*/*.a
和*/*.b
. 然後將每個單詞擴展為一個 glob 模式。第一個擴展為dir/file.a
,第二個擴展為自身,因為它不匹配任何內容。所有這一切意味著,如果你使用mv
and notecho
,mv
應該嘗試移動 2 個文件:dir/file.a
(fine) 和*/*.b
(no such file)。這是在大多數 shell 中預設發生的情況,例如sh
andksg
和bash
。zsh 預設選項設置是
null_glob
未設置和nomatch
已設置。腳本使用預設選項設置執行(除非您在~/.zshenv
or中更改它們,否則/etc/zshenv
您不應該這樣做)。這意味著在腳本中,您會得到:% mkdir dir % touch dir/file.a % ls file.a ls: cannot access file.a: No such file or directory % cat script.sh #!/usr/bin/zsh echo */*.{a,b} . % ./script.sh ./script.sh:2: no matches found: */*.b
由於
*/*.b
不匹配任何內容,因此由於nomatch
.如果你在/命令
setopt nonomatch
之前插入腳本,你會回到我上面描述的錯誤行為:它試圖移動一個不存在的文件。echo``mv
如果你在/命令
setopt null_glob
之前插入腳本 ,你會得到你在互動式 shell 中得到的行為,這是有效的。echo``mv