Por que uma geração de nome de arquivo com falha faz com que o zsh pare de processar um script?

3

Eu estava tentando escrever um script curto que gravaria todos os programas executáveis encontrados em $PATH :

for dir in $(tr ':' ' ' <<<"${PATH}"); do
  for pgm in $dir/*; do
    if command -v "${pgm}" >/dev/null 2>&1; then
      echo "${pgm}"
    fi
  done
done | sort >file

No bash, ele funciona como esperado, mas o zsh pára de processar o script assim que a geração do nome do arquivo falha no loop interno:

for pgm in $dir/*; do
           ^^^^^^
  ...
done

Como resultado, como meu $PATH contém um diretório que não contém nenhum arquivo ( /usr/local/sbin ), em zsh, o script falha ao gravar os executáveis encontrados nos diretórios posteriormente.

Este é outro código que mostra o mesmo problema:

for f in /not_a_dir/*; do
  echo 'in the loop'
done
echo 'after the loop'

No bash, este comando gera:

in the loop
after the loop

E sai com o código 0 .

Enquanto em zsh, o mesmo comando gera:

no matches found: /not_a_dir/*

E sai com o código 1 .

A diferença de comportamento entre os shells parece vir da opção nomatch , que é descrita em man zshoptions :

NOMATCH (+3) <C> <Z>

If a pattern for filename generation has no matches, print an error, instead of leaving it unchanged in the argument list. This also applies to file expansion of an initial ~ or =.

E também explicado em man zshexpn (section FILENAME GENERATION):

The word is replaced with a list of sorted filenames that match the pattern. If no matching pattern is found, the shell gives an error message, unless the NULL_GLOB option is set, in which case the word is deleted; or unless the NOMATCH option is unset, in which case the word is left unchanged.

Porque se eu cancelar a configuração de nomatch , o zsh se comportará como o bash:

unsetopt nomatch
for f in /not_a_dir/*; do
  echo 'in the loop'
done
echo 'after the loop'

Agora eu entendo a diferença de comportamentos entre o bash e o zsh, e porque o script gera um erro no zsh, mas eu quero entender por que uma geração de nome de arquivo falhada faz com que o zsh pare imediatamente de processar um script. Então, tentei reproduzir o mesmo problema substituindo a geração de nome de arquivo com falha por um comando com falha (executando not_a_cmd ):

for f in ~/*; do
  not_a_cmd
done
echo 'after the loop'

Mas a saída deste script é quase idêntica em ambos os shells (além das mensagens de erro devidas a not_a_cmd ). Em particular, ambas as conchas são impressas:

after the loop

E ambos os shells saem com o código 0 .

Por que uma geração de nome de arquivo com falha (como for f in /not_a_dir/* ) faz com que o zsh pare de processar um script, mas não um comando com falha (como not_a_cmd )?

Estou usando zsh 5.6.2-dev-0 (x86_64-pc-linux-gnu) .

    
por user938271 31.10.2018 / 05:19

0 respostas

Tags