Eu estava tentando fazer backup de alguns arquivos via SSH, mas em vez dos que tar
eu queria, consegui minha pasta pessoal. Fiz mais alguns testes e tudo se resume a isso:
ssh root@server /bin/sh -c "cd /boot && ls -l"
Qual a minha surpresa lista arquivos /root
não /boot
. Mas se eu executar o /bin/sh
comando inteiro a partir de um terminal, ele corretamente cd
imprimirá os /boot
arquivos.
O que está acontecendo aqui?
shell
ssh
cd-command
Ambroz Bizjak
fonte
fonte
ssh root@server /bin/sh -c "ls -l /boot"
?Respostas:
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, concatena todos os argumentos em uma string e os executa por meio de um shell remoto. Isso se destaca como uma das principais falhas de design do ssh, na minha opinião ... na maioria das vezes, é uma ferramenta unix bem comportada, mas quando chega a hora de especificar um comando, optamos por usar uma única string monolítica em vez de um argv, como foi projetado para MSDOS ou algo assim!
Como o ssh passará seu comando como uma única sequência
sh -c
, você não precisará fornecer o seu própriosh -c
. Quando você faz, o resultado écom a citação original perdida. Portanto, os comandos separados por
&&
são:O primeiro deles executa um shell com o texto de comando "cd" e
$0
="boot"
. O comando "cd" é concluído com êxito,$0
é irrelevante e/bin/sh -c
indica sucesso, e entãols -l
acontece.fonte
ssh
se comporte assim, se não fosse, teria que ser chamadosexec
, nãossh
.ssh
é a versão segura dersh
(que se comportou da mesma maneira nesse sentido) erlogin
(rsh
chamadarlogin
quando não passou por uma linha de comando). É lamentável que isso também não seja implementadorexec
."`printf "%q " "$@"`"
with bash'sprintf
para citar uma string ou strings com escape de shell.É uma questão 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 intermediário para criar uma sequência. Portanto, o comando remoto que você está executando remotamente é
/bin/sh -c cd /boot && ls -l
(sem aspas, porque as aspas no seu comando foram interpretadas pelo shell local)./bin/sh -c cd /boot
runs/bin/sh
e diz-lhe para executar o comandocd
e também para conjunto$0
para/boot
. Feito isso, o shell pai (o iniciado porsshd
) é executadols -l
.No seu caso, basta remover o
sh -c
que é completamente inútil, a menos que seu shell remoto (conforme indicado em/etc/passwd
ou em outro banco de dados de senhas) não entenda esse comando.Se você precisar chamar um shell diferente, deverá citar o comando remoto para protegê-lo da expansão pelo shell remoto chamado por
sshd
. Por exemplo, se o seu shell de login é traço e você deseja executar um comando bash:fonte
Eu acho que tem mais a ver com a forma como as opções estão sendo analisadas pelo shell. Por exemplo, isso funciona:
Isso tem o mesmo problema que o seu comando:
Se você ativar o
-v
switch,ssh
poderá ver o que está acontecendo:1º comando:
2º comando:
Normalmente, ao enviar comandos,
ssh
você deve prestar atenção especial às aspas e agrupar aspas entre aspas, pois 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 a citação
ssh
, como a seguir. Isso executará o comando no servidor remoto, mas coletará os resultados em um arquivo localmente no sistema em que você executou ossh
comando:ou isto, em que você tar um diretório em um servidor remoto e o cria no sistema local:
Referências
fonte
Normalmente, você não precisa especificar qual shell usar. Isso funciona:
Mas se o seu shell padrão for problemático, certifique-se de citar todo o comando, incluindo a chamada do shell. Um dos seguintes trabalhos
fonte
cd /boot && pwd
trabalhe em todos os invólucros das principais famílias (Bourne, csh, rc),/bin/sh -c "cd /boot && pwd"
não funcionaria se o shell remoto for darc
família onde"
não é especial.