![对 zsh 中特定文件和文件类型是否存在进行条件测试](https://linux22.com/image/122700/%E5%AF%B9%20zsh%20%E4%B8%AD%E7%89%B9%E5%AE%9A%E6%96%87%E4%BB%B6%E5%92%8C%E6%96%87%E4%BB%B6%E7%B1%BB%E5%9E%8B%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%E8%BF%9B%E8%A1%8C%E6%9D%A1%E4%BB%B6%E6%B5%8B%E8%AF%95.png)
我想检查当前目录中是否存在扩展名为abc
,bak
或tmp
,的文件或者一个名为tmpout.wrk
.我无法让这个(最终是函数的一部分)在 zsh 中工作。它可以运行,但无法正确检测。
if [[ -f *.(abc|bak|tmp) || -f tmpout.wrk ]]; then
echo 'true';
else
echo 'false';
fi
答案1
要测试 glob 是否至少返回一个文件,您可以执行以下操作:
if ()(($#)) (*.(abc|bak|tmp)|tmpout.wrk)(NY1); then
echo true
else
echo false
fi
要检查符号链接解析后至少其中一个是常规文件,请添加-.
glob 限定符:
if ()(($#)) (*.(abc|bak|tmp)|tmpout.wrk)(NY1-.); then
echo true
else
echo false
fi
()(($#))
是一个匿名函数,我们将 glob 的结果传递给它。该函数的主体 ((($#))
) 仅测试参数的数量是否为非零。N
作为该 glob 的 glob 限定符打开nullglob
(当 glob 与任何文件不匹配时,使 glob 扩展为空)Y1
限制最多扩展一个文件。这是一个性能优化。-
使下一个 glob 限定符被考虑后符号链接解析。.
仅考虑常规文件(因此这里常规文件或符号链接最终解析为常规文件,就像命令[ -f file ]
一样)。
答案2
长话短说
set -o extendedglob
if [[ -n *.(abc|bak|tmp)(#qN) || -f tmpout.wrk ]]; then
否则,通过一些测试,
% [[ -f /etc/passwd ]] && echo yea
yea
% echo /etc/passw?
/etc/passwd
% [[ -f /etc/passw? ]] && echo yea
%
好吧,zsh
在这里做什么?
% set -x
% [[ -f /etc/passw? ]] && echo yes
+zsh:13> [[ -f '/etc/passw?' ]]
%
它们的单引号肯定不会产生任何结果。让我们搜索[[
... man zshall
,然后搜索CONDITIONAL EXPRESSIONS
...啊,这是关于文件名生成的一些内容:
Filename generation is not performed on any form of argument to condi-
tions. However, it can be forced in any case where normal shell expan-
sion is valid and when the option EXTENDED_GLOB is in effect by using
an explicit glob qualifier of the form (#q) at the end of the string.
A normal glob qualifier expression may appear between the `q' and the
closing parenthesis; if none appears the expression has no effect
beyond causing filename generation. The results of filename generation
are joined together to form a single word, as with the results of other
forms of expansion.
This special use of filename generation is only available with the [[
syntax. If the condition occurs within the [ or test builtin commands
then globbing occurs instead as part of normal command line expansion
before the condition is evaluated. In this case it may generate multi-
ple words which are likely to confuse the syntax of the test command.
For example,
[[ -n file*(#qN) ]]
produces status zero if and only if there is at least one file in the
current directory beginning with the string `file'. The globbing qual-
ifier N ensures that the expression is empty if there is no matching
file.
所以考虑到这一点,
% [[ -f /etc/passw?(#q) ]] && echo yes
+zsh:14> [[ -f /etc/passwd ]]
+zsh:14> echo yes
yes
% exec zsh -l
对于您的情况,考虑可能没有文件的情况:
% mkdir dir
% cd dir
% touch blah.foo
% [[ -f *.(foo|bar|baz)(#q) ]] && echo yea
yea
% rm blah.foo
% [[ -f *.(foo|bar|baz)(#q) ]] && echo yea
zsh: no matches found: *.(foo|bar|baz)(#q)
% [[ -f *.(foo|bar|baz)(#qN) ]] && echo yea
% touch a.foo b.foo
% [[ -f *.(foo|bar|baz)(#qN) ]] && echo yea
% [[ -n *.(foo|bar|baz)(#qN) ]] && echo yea
yea
%
(尽管-n
我们只检查 glob 是否匹配,而不检查相应的文件是否是常规文件)。