jhr*_*jhr 3 shell scripting zsh wildcards
我目前正在编写一个非常简单的 zsh 脚本。我经常做的是这样的:
mv */*.{a,b} .
Run Code Online (Sandbox Code Playgroud)
当我在 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
Run Code Online (Sandbox Code Playgroud)
所以,这有效,但作为脚本:
% 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
Run Code Online (Sandbox Code Playgroud)
那么,有什么不同呢?我究竟做错了什么?
两者的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 .
Run Code Online (Sandbox Code Playgroud)
扩展分两步进行。首先,*/*.{a,b}扩展为2个词:*/*.a和*/*.b。然后每个单词被扩展为一个 glob 模式。第一个扩展为dir/file.a,第二个扩展为自身,因为它不匹配任何内容。所有这一切意味着,如果您使用mv和 不echo,mv应该尝试移动 2 个文件:(dir/file.a很好)和*/*.b(没有这样的文件)。这是大多数 shell 中默认发生的情况,例如shandksg和bash。
zsh 默认选项设置是null_glob未设置和nomatch已设置。脚本使用默认选项设置运行(除非您在~/.zshenv或 中更改它们/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
Run Code Online (Sandbox Code Playgroud)
由于*/*.b不匹配任何内容,因此您会因nomatch.
如果你setopt nonomatch在echo/mv命令之前插入脚本,你会回到我上面描述的错误行为:它试图移动一个不存在的文件。
如果你setopt null_glob在echo/mv 命令之前插入脚本,你会得到你在交互式 shell 中得到的行为,这是有效的。
| 归档时间: |
|
| 查看次数: |
1171 次 |
| 最近记录: |