Você não esperaria:
var='echo test && reboot'
echo $var
Para produzir test e depois reiniciar, você faria?
Em vez disso, gera echo test && reboot
Isso é o mesmo para
var='echo test && reboot'
$var
Agora, onde se torna confuso é que na maioria dos shells parecidos com o Bourne, ele não falha com um erro que diz que o comando echo test && reboot não foi encontrado. Em vez disso, e a menos que você tenha modificado $IFS , ele gerará test && reboot .
Isso porque, nesses shells, deixar uma variável sem aspas aplica algum tipo de operador split + glob.
Como $var não é citado, ele é dividido em palavras (de acordo com o parâmetro $IFS special): echo , test , && , reboot e o comando a ser executado é derivado do primeiro ( echo ) e todas as palavras passadas como argumentos para esse comando. && é um argumento para echo lá. Apenas um literal && sem aspas será entendido como o operador && da linguagem sh . Como em C, var="foo, bar"; printf(var) não significa que dois argumentos são passados para printf apenas porque var contém , , que é um operador na sintaxe da linguagem C.
Na verdade, se voltarmos na história para as primeiras versões do Unix no início dos anos 70, o sh (hoje chamado de Thompson shell ) teria rodado reboot lá . Bem, sh naquela época não suportava variáveis, mas tinha parâmetros posicionais.
Aqui usando o Unix V1 em um emulador PDP11:
$ cat myscript
echo $1
$ sh myscript 'echo test; reboot'
echo test
No command
$ ls -l /bin/sh
total 12
88 lxrwr- 1 sys 5312 Jan 1 00:00:00 sh
(felizmente, não havia nenhum comando reboot , portanto, o erro No command ).
Isso pode parecer loucura pelo padrão atual, mas lembre-se de que o Unix V1 era executado em máquinas com algumas centenas de kilobytes de memória e megabytes de armazenamento, então as coisas tinham que ser mantidas simples na época. Veja como sh é significativamente menor que /bin/true (o comando que não faz nada) em um sistema moderno (27KB no meu sistema (sem contar o vinculador dinâmico ou as bibliotecas dinâmicas com as quais ele está vinculado) contra 5KB para esse sh).
O Unix V7 no final dos anos 70 veio com o shell Bourne, o novo sh . Muito mais avançado, mas ainda não quebrou completamente a compatibilidade com o seu antecessor. O mesmo para o csh que ocorreu mais ou menos na mesma hora no BSD. É provavelmente a principal razão para esse comportamento desajeitado da shell Bourne: a expansão dos parâmetros ainda sofre algumas formas de expansão, como a divisão em palavras e também globbing (mas não tanto quanto a reinterpretação da linguagem sh shish como no início do Unix shells como isso seria loucura), por compatibilidade retroativa com as conchas Thomson.
Alguns shells como rc , fish ou zsh (aquele que é um shell parecido com o Bourne) acabaram sendo corrigidos posteriormente, mas muitos incluindo bash mantiveram compatibilidade retroativa com o shell Bourne.
Agora, se você quiser interpretar uma string como código shell, é para isso que serve o comando eval :
eval "$var"
(observe as aspas para evitar o split + globbing em shells parecidos com Bourne).
Mas se você quiser armazenar código em uma variável, faria muito mais sentido usar uma função como em outros idiomas:
f() { echo test && reboot; }