Eu li que você precisa de aspas duplas para expandir variáveis, por exemplo
if [ -n "$test" ]; then echo '$test ok'; else echo '$test null'; fi
funcionará como esperado, enquanto
if [ -n $test ]; then echo '$test ok'; else echo '$test null'; fi
sempre dirá $test ok
mesmo se $test
for nulo.
mas então por que não precisamos de aspas echo $test
?
echo
, espaços extras e novas linhas serão removidos.Respostas:
Você sempre precisa de aspas em torno de variáveis em todos os contextos de lista , ou seja, em todos os lugares a variável pode ser expandida para vários valores, a menos que você queira os três efeitos colaterais de deixar uma variável sem aspas.
Os contextos de lista incluem argumentos para comandos simples como
[
ouecho
, asfor i in <here>
atribuições a matrizes ... Existem outros contextos em que as variáveis também precisam ser citadas. O melhor é sempre citar variáveis, a menos que você tenha uma boa razão para não fazê-lo.Pense na ausência de aspas (em contextos de lista) como o operador split + glob .
Como se
echo $test
fosseecho glob(split("$test"))
.O comportamento do shell é confuso para a maioria das pessoas, porque na maioria das outras linguagens, você coloca aspas em torno de cadeias fixas, como
puts("foo")
, e não em torno de variáveis (comoputs(var)
), enquanto no shell é o contrário: tudo é string em shell, colocando aspas em tudo seria complicado, vocêecho test
, você não precisa"echo" "test"
. No shell, as aspas são usadas para outra coisa: impedir algum significado especial de alguns caracteres e / ou afetar o comportamento de algumas expansões.Em
[ -n $test ]
ouecho $test
, o shell é dividido$test
(em branco por padrão) e, em seguida, executa a geração do nome do arquivo (expanda todos os*
padrões '?' ... para a lista de arquivos correspondentes) e passa essa lista de argumentos para os comandos[
ouecho
.Mais uma vez, pense nisso como
"[" "-n" glob(split("$test")) "]"
. Se$test
estiver vazio ou contiver apenas espaços em branco (spc, tab, nl), o operador split + glob retornará uma lista vazia, então[ -n $test ]
será"[" "-n" "]"
, que é um teste para verificar se "-n" é a sequência vazia ou não. Mas imagine o que teria acontecido se$test
fosse "*" ou "= foo" ...Em
[ -n "$test" ]
,[
é passado os quatro argumentos"["
,"-n"
,""
e"]"
(sem as aspas), que é o que queremos.Se é
echo
ou[
não faz diferença, é exatamente isso queecho
produz a mesma coisa, seja passado um argumento vazio ou nenhum argumento.Consulte também esta resposta a uma pergunta semelhante para obter mais detalhes sobre o
[
comando e a[[...]]
construção.fonte
A resposta do @ h3rrmiller é boa para explicar por que você precisa das aspas para
if
(ou melhor,[
/test
), mas eu realmente diria que sua pergunta está incorreta.Experimente os seguintes comandos e você verá o que quero dizer.
Sem as aspas, a substituição da variável faz com que o segundo comando se expanda para:
e os vários espaços são recolhidos em um único:
Com as aspas, os espaços são preservados.
Isso acontece porque quando você cita um parâmetro (se o parâmetro é passado para
echo
,test
ou algum outro comando), o valor desse parâmetro é enviado como um valor para o comando. Se você não citar, o shell faz sua mágica normal de procurar espaços em branco para determinar onde cada parâmetro começa e termina.Isso também pode ser ilustrado pelo seguinte programa C (muito, muito simples). Tente o seguinte na linha de comando (você pode fazê-lo em um diretório vazio para não arriscar substituir algo).
e depois...
Após a execução
paramtest
,$?
manterá o número de parâmetros que foram passados (e esse número será impresso).fonte
É tudo sobre como o shell interpreta a linha antes que um programa seja executado.
Se a linha for lida
echo I am $USER
, o shell a expandeecho I am blrfl
eecho
não tem idéia se a origem do texto é uma expansão literal ou variável. Da mesma forma, se uma linha lerecho I am $UNDEFINED
, o shell se expandirá$UNDEFINED
em nada e os argumentos do eco serãoI am
, e é o fim disso. Comoecho
funciona muito bem sem argumentos,echo $UNDEFINED
é completamente válido.Seu problema com
if
não está realmente certoif
, porqueif
apenas executa o programa e os argumentos que o seguem e executa athen
parte se o programa sair0
(ou aelse
parte se houver um e o programa sair não0
):Quando você
if [ ... ]
faz uma comparação, não usa primitivas embutidas no shell. Você está realmente instruindo o shell a executar um programa chamado[
que é um superconjunto muito pequeno dotest(1)
que requer seu último argumento]
. Ambos os programas são encerrados0
se a condição de teste for verdadeira e1
se não.A razão pela qual alguns testes são interrompidos quando uma variável é indefinida é porque
test
você não vê que está usando uma variável. Ergo,[ $UNDEFINED -eq 2 ]
quebras porque, quando o shell termina, tudotest
indica argumentos-eq 2 ]
, o que não é um teste válido. Se você fizesse isso com algo definido, como, por exemplo[ $DEFINED -ne 0 ]
, isso funcionaria porque o shell o expandiria em um teste válido (por exemplo,0 -ne 0
).Há uma diferença semântica entre
foo $UNDEFINED bar
, que se expande para dois argumentos (foo
ebar
) porque$UNDEFINED
correspondeu ao seu nome. Compare isso comfoo "$UNDEFINED" bar
, que se expande para três argumentos (foo
, uma string vazia e `bar). As aspas forçam o shell a interpretá-las como um argumento sobre se há algo entre elas ou não.fonte
Sem aspas
$test
pode expandir para ser mais de uma palavra, portanto, precisa ser citada para não quebrar a sintaxe, pois cada opção dentro do[
comando espera um argumento que é o que as aspas fazem (faz o que se$test
expande para um argumento)O motivo pelo qual você não precisa de aspas para expandir uma variável
echo
é porque ela não está esperando um argumento. Simplesmente imprimirá o que você mandou. Portanto, mesmo que se$test
expanda para 100 palavras, o eco ainda o imprimirá.Dê uma olhada no Bash Pitfalls
fonte
echo
?echo
. O que faz você pensar o contrário?echo $test
e ele funciona (ele gera o valor de $ test)Os parâmetros vazios são removidos se não estiverem citados:
O comando chamado não vê que havia um parâmetro vazio na linha de comando do shell. Parece que [está definido para retornar 0 para -n sem nada a seguir. Por que.
A citação também faz diferença para o eco em vários casos:
fonte
echo
, é a concha. Você veria o mesmo comportamento comls
. Tentetouch '*'
algum tempo se você se sentir aventureiro.:)