Eu acho que o problema é que existem três shells envolvidos:
- o shell local que processa o comando
ssh
; - o shell remoto que
ssh
chama para processar o comando no host de destino; - o shell adicional chamado pelo
sh -c
no comando remoto.
As citações fazem duas coisas:
- eles param o shell local avaliando quaisquer variáveis no shell local (1);
- eles garantem um único parâmetro para o controle remoto
sh -c
.
Assim, ssh
vê quatro parâmetros: user@host
, sh
, -c
e o comando necessário. No entanto, as citações são removidas ao criar o quarto parâmetro e quando o shell remoto (2) recebe seus parâmetros, ele interpreta o $(false)
em si e o código de conclusão é definido em seu próprio ambiente antes de chamar o subcama (3).
O shell adicional (3) vê, assim, DIR= && echo ok || echo fail
e DIR=
é um comando perfeitamente válido, sem erros, daí a ramificação ok
.
Você pode ver o mesmo efeito em:
sh -c 'sh -c "DIR=$(false) && echo ok || echo not"'
ou:
sh -c "sh -c 'DIR=$(false) && echo ok || echo not'"
Em ambos os casos, funciona "corretamente" se você colocar um \
antes do $
, pois isso impede que o segundo shell expanda $(false)
. Eu usei aspas duplas para tornar os mecanismos mais claros - se você preferir, há um pouco tortuoso:
sh -c 'sh -c '\''DIR=$(false) && echo ok || echo not'\'
O exemplo de Richard funciona, porque toda a expansão é feita no único shell remoto, e um false;
inicial não tem efeito no comando subseqüente. Não tem nada a ver com o tópico discutido em seu link.