Status de saída incorreto na avaliação da substituição de comandos via ssh?

1

Eu tenho o seguinte comando shell simples que estou esperando falhar e faz no meu local:

$ DIR=$(false) && echo ok || echo fail
fail
$ sh -c 'DIR=$(false) && echo ok || echo fail'
fail

Mas quando eu estou passando este comando via ssh, ele não funciona mais como esperado:

$ ssh user@host sh -c 'DIR=$(false) && echo ok || echo fail'
ok

Então, não tenho certeza de onde está o problema. Eu já estou usando o apóstrofo, para evitar expansão de variáveis muito cedo .

O que está acontecendo e como fazer com que a substituição do comando funcione corretamente com base no código de saída retornado da atribuição de variável?

Outra anomalia que encontrei com o seguinte exemplo:

$ ssh user@host sh -c 'echo 1; echo 2;'

2

que imprime apenas 2, em vez de imprimir ambos 1 e 2.

    
por kenorb 10.02.2015 / 01:33

2 respostas

2

Eu acho que o problema é que existem três shells envolvidos:

  1. o shell local que processa o comando ssh ;
  2. o shell remoto que ssh chama para processar o comando no host de destino;
  3. 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.

    
por 10.02.2015 / 04:03
1

Isso deve funcionar como esperado:

ssh user@host 'DIR=$(false) && echo ok || echo fail'

Parece que, quando invocada como acima, a primeira instrução no pipeline de shell não funcionará se for uma atribuição de variável.

Estranhamente, isso também funciona como esperado:

ssh user@host sh -c 'false; DIR=$(false) && echo ok || echo fail'

Não tenho 100% de certeza do que está acontecendo aqui, mas isso pode estar relacionado a esta pergunta: link

    
por 10.02.2015 / 02:07