Por que o comando 'cd' não funciona via SSH?

35

Eu estava tentando fazer o backup de alguns arquivos via SSH, mas em vez de tar 'os que eu queria, consegui minha pasta pessoal. Fiz alguns testes adicionais e tudo se resume a isso:

ssh root@server /bin/sh -c "cd /boot && ls -l"

O que, para minha surpresa, lista arquivos em /root não /boot . Mas se eu executar o comando /bin/sh inteiro a partir de um terminal, ele é apropriadamente cd s e imprime os arquivos /boot .

O que está acontecendo aqui?

    
por Ambroz Bizjak 27.06.2013 / 01:33

4 respostas

29

O ssh não permite que você especifique um comando com precisão, como você fez, como uma série de argumentos a serem passados para o execvp no host remoto. Em vez disso, ele concatena todos os argumentos em uma string e os executa por meio de um shell remoto. Isso se destaca como uma grande falha de design em ssh na minha opinião ... é uma ferramenta unix bem comportada na maioria das formas, mas quando chega a hora de especificar um comando ele escolheu usar uma única string monolítica em vez de uma argv, como foi projetado para MSDOS ou algo assim!

Como o ssh passará seu comando como uma única string para sh -c , você não precisa fornecer seu próprio sh -c . Quando você faz, o resultado é

sh -c '/bin/sh -c cd /boot && ls -l'

com a citação original perdida. Então os comandos separados por && são:

'/bin/sh -c cd /boot'
'ls -l'

O primeiro deles executa um shell com o texto de comando "cd" e $0 = "boot" . O comando "cd" é concluído com sucesso, o $0 é irrelevante e o /bin/sh -c indica sucesso, então o ls -l acontece.

    
por 27.06.2013 / 02:16
33

É um problema de citação. O ssh já executa o comando que você passa em um shell. Quando você passa vários parâmetros, eles são concatenados com um espaço entre eles para construir uma string. Portanto, o comando remoto que você está executando remotamente é /bin/sh -c cd /boot && ls -l (sem aspas, porque as aspas em seu comando foram interpretadas pelo shell local).

/bin/sh -c cd /boot corre /bin/sh e diz para executar o comando cd e também para definir $0 para /boot . Feito isso, o shell pai (aquele lançado por sshd ) executa ls -l .

No seu caso, apenas remova o sh -c , que é completamente inútil, a menos que seu shell remoto (como indicado em /etc/passwd ou outro banco de dados de senha) não entenda este comando.

ssh root@server "cd /boot && ls -l"

Se você precisar chamar um shell diferente, deverá citar o comando remoto para protegê-lo da expansão pelo shell remoto invocado por sshd . Por exemplo, se seu shell de login for traço e você desejar executar um comando bash:

ssh root@server 'bash -c "cd ~bob && ls -l"'
    
por 27.06.2013 / 02:12
8

Eu acho que tem mais a ver com como as opções estão sendo analisadas pelo shell. Por exemplo, isso funciona:

$ ssh root@server /bin/sh -c '"cd /boot && ls -l"'

Isso tem o mesmo problema que seu comando:

$ ssh root@server /bin/sh -c 'cd /boot && ls -l'

Se você ativar a opção -v para ssh , poderá ver o que está acontecendo:

1º comando:

debug1: Sending command: /bin/sh -c "cd /boot && ls -l"

2º comando:

debug1: Sending command: /bin/sh -c cd /boot && ls -l

Normalmente, ao enviar comandos por meio de ssh , é preciso prestar atenção especial às cotações e agrupar as aspas entre aspas, à medida que as várias camadas as separam. Também não se incomode em enviar /bin/sh .

Você pode fazer algo muito útil depois de entender as citações de ssh , como as que se seguem. Isso executará o comando no servidor remoto, mas coletará os resultados em um arquivo localmente no sistema em que você executou o comando ssh :

$ ssh root@server 'free -m' > /tmp/memory.status

ou isto, onde você coloca um diretório em um servidor remoto e o cria no sistema local:

$ ssh remotehost 'tar zcvf - SOURCEDIR' | cat > DESTFILE.tar.gz

Referências

por 27.06.2013 / 02:15
3

Normalmente, você não precisa especificar qual shell usar. Isso funciona:

ssh user@host "cd /boot && pwd"

Mas se o seu shell padrão é problemático, apenas certifique-se de citar o comando inteiro , incluindo a invocação do shell. Qualquer um dos seguintes trabalhos

ssh user@host '/bin/sh -c "cd /boot && pwd"'
ssh user@host "/bin/sh -c \"cd /boot && pwd\""
    
por 27.06.2013 / 05:27