对 zsh 中特定文件和文件类型是否存在进行条件测试

对 zsh 中特定文件和文件类型是否存在进行条件测试

我想检查当前目录中是否存在扩展名为abc,baktmp,的文件或者一个名为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 是否匹配,而不检查相应的文件是否是常规文件)。

相关内容