zsh で特定のファイルとファイル タイプが存在するかどうかを条件付きでテストする

zsh で特定のファイルとファイル タイプが存在するかどうかを条件付きでテストする

abc現在のディレクトリに、、bakまたはの拡張子を持つファイルが存在するかどうかを確認したいtmpまたはという名前のファイルtmpout.wrk。これ (最終的には関数の一部) を zsh で動作させることができません。実行はされますが、適切に検出されません。

if [[ -f *.(abc|bak|tmp) || -f tmpout.wrk ]]; then 
    echo 'true'; 
else 
    echo 'false'; 
fi

答え1

glob が少なくとも 1 つのファイルを返すことをテストするには、次のようにします。

if ()(($#)) (*.(abc|bak|tmp)|tmpout.wrk)(NY1); then
  echo true
else
  echo false
fi

シンボリックリンクの解決後に少なくとも 1 つが通常のファイルであることを確認するには、-. glob 修飾子を追加します。

if ()(($#)) (*.(abc|bak|tmp)|tmpout.wrk)(NY1-.); then
  echo true
else
  echo false
fi
  • ()(($#))は、グロブの結果を渡す匿名関数です。その関数の本体 ( (($#))) は、引数の数がゼロでないかどうかをテストするだけです。

  • Nglob 修飾子がnullglobその glob に対してオンになる (どのファイルにも一致しない場合は glob が何も展開されない)

  • Y1展開を最大 1 つのファイルに制限します。これはパフォーマンスの最適化です。

  • -次のグロブ修飾子を考慮するシンボリックリンクの解決。

  • .通常のファイルのみを考慮します (したがって、ここでは通常のファイルまたはシンボリックリンクは、コマンドと同様に、最終的に通常のファイルに解決されます[ -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
% 

(ただし、 では、-nglob が一致するかどうかのみをチェックし、対応するファイルが通常のファイルであるかどうかはチェックしません)。

関連情報