O caractere Glob dentro da variável se expande no bash, mas não no zsh

1

Estou vendo um problema com o zsh, em que um caractere glob dentro de uma variável não está expandindo como seria de se esperar. O exemplo a seguir explica melhor isso.

$ echo $0
-bash

$ echo $HOME/Downloads/zsh-test/*
/Users/bruce/Downloads/zsh-test/file1 /Users/bruce/Downloads/zsh-test/file2 /Users/bruce/Downloads/zsh-test/file3 /Users/bruce/Downloads/zsh-test/file4

$ file=*; echo $HOME/Downloads/zsh-test/$file
/Users/bruce/Downloads/zsh-test/file1 /Users/bruce/Downloads/zsh-test/file2 /Users/bruce/Downloads/zsh-test/file3 /Users/bruce/Downloads/zsh-test/file4

Macbook% echo $0
zsh

Macbook% echo $HOME/Downloads/zsh-test/*
/Users/bruce/Downloads/zsh-test/file1 /Users/bruce/Downloads/zsh-test/file2 /Users/bruce/Downloads/zsh-test/file3 /Users/bruce/Downloads/zsh-test/file4

Macbook% file=*; echo $HOME/Downloads/zsh-test/$file
/Users/bruce/Downloads/zsh-test/*

Eu esperava que o último comando se expandisse como acontece no bash. Alguma ideia do que estou fazendo errado?

    
por Bruce Johnson 08.08.2018 / 21:38

1 resposta

6

Essa seria a primeira vez que eu vejo alguém reclamando sobre isso (nós vemos com mais frequência as pessoas reclamando sobre isso não fazendo a divisão da palavra na expansão do parâmetro).

A maioria das pessoas espera

echo $file

para gerar o conteúdo da variável $file e ficar irritado quando shells como bash não (um comportamento herdado do shell Bourne, infelizmente não corrigido pelo ksh e especificado pelo POSIX para o interpretador sh ) e isso está causando muitos bugs e vulnerabilidades de segurança e é por isso que você precisa citar todas as variáveis nesses shells.

Veja por exemplo: Implicações de segurança de esquecer de citar uma variável em shells bash / POSIX

Eu vejo que você está esperando isso também porque está escrevendo echo $0 e não echo "$0" .

zsh corrigiu isso. Não faz globbing nem quebra de palavras por padrão na expansão de parâmetros. Você precisa solicitá-los explicitamente:

  • echo $=file : executa a divisão de palavras
  • echo $~file : executar globbing
  • echo $=~file : executa ambos

Ou você pode ativar as opções globsubst e shwordsplit para obter o mesmo comportamento de shells semelhantes a Bourne (essas duas opções são ativadas quando zsh é invocado como sh para sh de compatibilidade) , mas eu não recomendaria isso, a menos que você precise de zsh para interpretar código escrito para outro shell (e, mesmo nesse caso, faria mais sentido interpretar esse código em sh emulation em um contexto local com emulate -L sh ) .

Aqui, nomeando sua variável file em

file=*

é enganoso se você pretende expandi-lo após a expansão¹

filename_pattern=*

faria mais sentido. Se você quiser que uma variável contendo o nome de todos os arquivos não ocultos no diretório atual, você faria:

files=(*)

ou:

files=(*(N))

para essa atribuição não falhar se não houver nenhum arquivo não oculto no diretório atual.

Ou seja, use uma atribuição de variável array . Isso funcionaria da mesma forma que em bash ou ksh93 (de onde vem essa sintaxe) mksh ou yash , exceto que zsh não tem outra falha na característica da Bourne shell pela qual o padrão é deixado não expandido quando não há correspondência.

¹Note que * é um nome perfeitamente válido para um arquivo no sistema Unix-like. Eu tomo um pouco de conforto em que rm -f -- $file remove o arquivo cujo nome está armazenado em $file , mesmo que esse arquivo seja chamado de * .

    
por 08.08.2018 / 21:50