As cotações são necessárias para a atribuição de variável local?

36

Posso omitir com segurança aspas no lado direito de uma atribuição local?

function foo {
    local myvar=${bar}
    stuff()
}

Estou interessado principalmente bash, mas qualquer informação sobre casos de canto em outros reservatórios é bem-vinda.

rahmu
fonte
Eu acho que não faz diferença se estiver em uma linha, como você tem em sua função. As atribuições não precisam ser citadas. Veja mpi-sb.mpg.de/departments/rg1/teaching/unixffb-ss98/…
jirib

Respostas:

41

Citações são necessários em export foo="$var"ou local foo="$var"(ou readonly, typeset, declaree outras variáveis que declara comandos ) em:

  • dash
  • o shdo NetBSD (também baseado no shell Almquist).
  • O shdo FreeBSD 9.2 ou anterior (veja a alteração na 9.3 )
  • yash
  • zshcom versões anteriores à 5.1 em kshou shemulação (ou para export var="$(cmd)"onde zshexecutaria a divisão de palavras de outra forma (sem globbing)).

Caso contrário, a expansão da variável estaria sujeita à divisão de palavras e / ou geração de nome de arquivo, como em qualquer argumento para qualquer outro comando.

E não são necessários em:

  • bash
  • ksh (todas as implementações)
  • o shdo FreeBSD 9.3 ou posterior
  • à base de cinzas do busybox sh(desde 2005)
  • zsh

Em zsh, split + glob nunca é feito na expansão de parâmetros, a menos que seja dentro shou kshemulado, mas split (não glob) é feito na substituição de comandos. Desde a versão 5.1, export/ locale outros comandos de declaração se tornaram comandos de palavra-chave dupla / embutidos, como nos outros shells acima, o que significa que a citação não é necessária, mesmo em sh/ kshemulation e até mesmo para substituição de comando.

Existem casos especiais em que é necessário citar mesmo nessas conchas, como:

a="b=some value"
export "$a"

Ou, de maneira mais geral, se algo restante do =(incluindo o =) for citado ou o resultado de alguma expansão (como export 'foo'="$var", export foo\="$var"ou export foo$((n+=1))="$var"(que $((...))também deve ser citado na verdade) ...). Ou, em outras palavras, quando o argumento para exportnão seria uma atribuição de variável válida se escrito sem o export.

Se o export/ localnome próprio comando é citado (mesmo em parte, como "export" a="$b", 'ex'port a="$b", \export a="$b", ou mesmo ""export a="$b"), as aspas em torno $bsão necessários excepto AT & T kshe mksh.

Se export/ localou parte dela é resultado de alguma expansão (como em cmd=export; "$cmd" a="$b"ou mesmo export$(:) a="$b") ou em coisas como dryrun=; $dryrun export a="$b"), então as aspas são necessárias em cada shell.

No caso de > /dev/null export a="$b", as cotações são necessárias em pdkshe alguns de seus derivados.

Pois command export a="$b", as aspas são necessárias em todos os shell, mas mkshe ksh93(com as mesmas ressalvas sobre commande exportnão sendo o resultado de alguma expansão).

Eles não são necessários em nenhum shell quando gravados:

foo=$var export foo

(essa sintaxe também é compatível com o shell Bourne, mas nas versões recentes do zsh, funcionando apenas quando em sh/ kshemulação).

(observe que var=value local varnão deve ser usado, pois o comportamento varia entre as conchas).

Observe também que o uso exportcom uma atribuição também significa que o status de saída de cmdin export var="$(cmd)"é perdido. Fazê-lo como export var; var=$(cmd)não tem esse problema.

Também tenha cuidado com este caso especial com bash:

$ bash -c 'IFS=; export a="$*"; echo "$a"' bash a b
ab
$ bash -c 'IFS=; export a=$*; echo "$a"' bash a b
a b

Meu conselho seria sempre citar.

Stéphane Chazelas
fonte
3
Observe que as zshaspas são necessárias local foo="$(cmd)"porque a divisão de palavras (mas não a geração do nome do arquivo) é executada para substituições de comandos sem KSH_TYPESETaspas (mas não para expansões de parâmetros sem aspas ), a menos que esteja ativada, nesse caso as aspas não são necessárias. Faz sentido? Não? Sempre cite tudo, a menos que você saiba exatamente o que está fazendo.
Matt
2
@ Matt, adoro a sua conclusão. : D É engraçado, a maior parte do que aprendi sobre scripts de shell veio dessa troca de pilha, então não percebi que sempre citar suas variáveis não é um conhecimento comum entre os roteiristas. Eu estou achando que eu tenho um monte de fixando-se a fazer de roteiros de produção escritos por pessoas que já existente não citar, e não sei exatamente o que estavam fazendo ....
Wildcard
3

Geralmente cito qualquer uso de variáveis ​​em que possa haver caracteres como espaços em branco. Caso contrário, você terá problemas como este:

#!/bin/bash

bar="hi bye"

function foo {
  local myvar=${bar}
  printf "%s\n" $myvar
  printf "%s\n" "$myvar"
}

foo

O uso da variável em uma atribuição não parece precisar de aspas, mas quando você a usar, como no exemplo, printfprecisará citá-la:

  printf "%s\n" "$myvar"

NOTA: Lembre - se de que a variável $IFSé o que governa quais são os caracteres separadores.

IFS    The  Internal  Field  Separator that is used for word splitting after 
       expansion and to split lines into words with the read builtin command. 
       The default value is ``<space><tab><newline>''.

Exemplo

Com a depuração ativada no Bash, podemos ver o que está acontecendo nos bastidores.

$ bash -x cmd.bash 
+ bar='hi bye'
+ foo
+ local 'myvar=hi bye'
+ printf '%s\n' hi bye
hi
bye
+ printf '%s\n' 'hi bye'
hi bye

No exposto acima, podemos ver que a variável $barfoi transferida para $myvarmas, quando fomos usar $myvar, tivemos que conhecer o conteúdo de $myvarquando fomos usá-la.

slm
fonte
2
a divisão de palavras não é o único problema com variáveis ​​não citadas, você também deve considerar a geração do nome do arquivo (também conhecido como globbing) (embora isso (ambos) não se aplique nas atribuições de variáveis ​​e para basheksh em local/ typeset... builtins especiais).
Stéphane Chazelas