Shell

zsh 擴展在非互動式腳本中的工作方式是否不同?

  • April 28, 2015

我目前正在研究一個非常簡單的 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預設選項設置錯誤。您可以通過使用echoas 命令而不是mv.

互動式地,看起來您已經null_glob設置了選項。根據zsh文件,預設情況下未設置該選項。未設置該選項會發生什麼取決於是否設置了另一個選項 , nomatch。使用nomatchunset ( 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,第二個擴展為自身,因為它不匹配任何內容。所有這一切意味著,如果你使用mvand not echomv應該嘗試移動 2 個文件:dir/file.a(fine) 和*/*.b(no such file)。這是在大多數 shell 中預設發生的情況,例如shandksgbash

zsh 預設選項設置是null_glob未設置和nomatch已設置。腳本使用預設選項設置執行(除非您在~/.zshenvor中更改它們,否則/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

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