Teste condicional para existência de arquivos e tipos de arquivos específicos em zsh

1

Desejo verificar no diretório atual a existência de arquivos com extensões de abc , bak ou tmp , ou um arquivo denominado tmpout.wrk . Eu não posso conseguir isso (eventualmente, parte de uma função) para trabalhar em zsh. Ele é executado, mas não consegue detectar corretamente.

if [[ -f *.(abc|bak|tmp) || -f tmpout.wrk ]]; then 
    echo 'true'; 
else 
    echo 'false'; 
fi
    
por Inbruges 29.11.2017 / 22:04

2 respostas

1

TL; DR

set -o extendedglob
if [[ -n *.(abc|bak|tmp)(#qN) || -f tmpout.wrk ]]; then

Caso contrário, através de alguns testes,

% [[ -f /etc/passwd ]] && echo yea
yea
% echo /etc/passw?
/etc/passwd
% [[ -f /etc/passw? ]] && echo yea
% 

Ok, o que o zsh está fazendo aqui?

% set -x
% [[ -f /etc/passw? ]] && echo yes
+zsh:13> [[ -f '/etc/passw?' ]]
% 

As citações simples não vão fazer nada. Vamos pesquisar em [[ em man zshall ... e depois pesquisar em CONDITIONAL EXPRESSIONS ... ah aqui está algo sobre geração de nome de arquivo:

   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.

Então, com isso em mente,

% [[ -f /etc/passw?(#q) ]] && echo yes
+zsh:14> [[ -f /etc/passwd ]]
+zsh:14> echo yes
yes
% exec zsh -l

E para o seu caso, respondendo pelo caso em que pode não haver arquivos:

% 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
% 

(embora com -n nós só verificamos que os globs combinam, não que os arquivos correspondentes sejam arquivos regulares).

    
por 29.11.2017 / 22:34
5

Para testar se o glob retorna pelo menos um arquivo, você pode fazer:

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

Para verificar se pelo menos um deles é um arquivo regular após a resolução do symlink, adicione o qualificador -. glob:

if ()(($#)) (*.(abc|bak|tmp)|tmpout.wrk)(NY1-.); then
  echo true
else
  echo false
fi
  • ()(($#)) é uma função anônima para a qual passamos o resultado das globs. O corpo dessa função ( (($#)) ) apenas testa que o número de argumentos é diferente de zero.

  • N como um qualificador glob ativa nullglob para esse glob (faz o glob se expandir para nada quando não corresponde a nenhum arquivo)

  • Y1 limita a expansão para no máximo um arquivo. É uma otimização de desempenho.

  • - faz com que o próximo qualificador de glob seja considerado após resolução de link simbólico.

  • . considera apenas os arquivos regulares (portanto, aqui os arquivos regulares ou os links simbólicos acabam resolvendo para um arquivo normal, como o comando [ -f file ] ).

por 29.11.2017 / 22:25