Conseguindo que o ssh execute um comando em segundo plano na máquina de destino

304

Esta é uma pergunta subsequente para Como você usa ssh em um script de shell? questão. Se eu quiser executar um comando na máquina remota que é executado em segundo plano nessa máquina, como faço para que o comando ssh retorne? Quando tento incluir apenas o e comercial (&) no final do comando, ele simplesmente trava. A forma exata do comando é semelhante a esta:

ssh user@target "cd /some/directory; program-to-execute &"

Alguma ideia? Uma coisa a observar é que os logons na máquina de destino sempre produzem um banner de texto e eu tenho chaves SSH configuradas para que nenhuma senha seja necessária.

dagorym
fonte

Respostas:

315

Eu tive esse problema em um programa que escrevi há um ano - a resposta é bastante complicada. Você precisará usar o nohup e o redirecionamento de saída, conforme explicado no artik da wikipedia no nohup , copiado aqui para sua conveniência.

Nohuping de trabalhos em segundo plano é, por exemplo, útil quando conectado via SSH, pois trabalhos em segundo plano podem fazer com que o shell seja interrompido no logout devido a uma condição de corrida [2]. Esse problema também pode ser superado redirecionando todos os três fluxos de E / S:

nohup myprogram > foo.out 2> foo.err < /dev/null &
Jax
fonte
1
Esses arquivos são criados no diretório atual. Portanto, o limite é a quantidade de espaço livre na partição. Claro que você também pode redirecionar para /dev/null.
27613 Frank Kusters
2
Alguma idéia sobre o plano de fundo do processo após a conclusão, solicitando avisos? (como um gpg --decrypt que está pedindo acabado para a senha)
isaaclw
Tentando iniciar um trabalhador resque em segundo plano usando nohup, mas ele não funciona .. :(
Infant Dev
1
Você pode, por favor, explicar o que < /dev/nullsignifica? Obrigado.
Qian Chen
1
Também no artigo da wikipedia sobre nohup: "Observe também que uma sessão SSH de fechamento nem sempre envia um sinal HUP para processos dependentes. Entre outros, isso depende se um pseudo-terminal foi alocado ou não." Portanto, embora estritamente o nohup nem sempre seja necessário, você é melhor a longo prazo do que sem.
Jax
254

Esta tem sido a maneira mais limpa de fazer isso por mim: -

ssh -n -f user@host "sh -c 'cd /whereever; nohup ./whatever > /dev/null 2>&1 &'"

A única coisa que corre depois disso é o comando real na máquina remota

Russ
fonte
7
-nnão é necessário, pois -fimplica-n
blissini
6
ssh -fdeixa o processo ssh conectado, apenas em segundo plano. As soluções / dev / null permitem que o ssh se desconecte rapidamente, o que pode ser preferível.
Beni Cherniavsky-Paskin
Esta solução funciona também para envio de comandos via ssh a um Syonology NAS
Stefan F
Preciso dos resultados de "ls -l" para aparecer no meu controle remoto, este comando não faz isso.
Siddharth
@ Sidharth Em seguida, redirecione para algum arquivo nomeado em vez de / dev / null.
sherrellbc 17/02
29

Redirecionar fd's

A saída precisa ser redirecionada com a &>/dev/nullqual redireciona stderr e stdout para / dev / null e é sinônimo de >/dev/null 2>/dev/nullor >/dev/null 2>&1.

Parantheses

A melhor maneira é usar sh -c '( ( command ) & )'where command é qualquer coisa.

ssh askapache 'sh -c "( ( nohup chown -R ask:ask /www/askapache.com &>/dev/null ) & )"'

Nohup Shell

Você também pode usar nohup diretamente para iniciar o shell:

ssh askapache 'nohup sh -c "( ( chown -R ask:ask /www/askapache.com &>/dev/null ) & )"'

Nice Launch

Outro truque é usar nice para iniciar o comando / shell:

ssh askapache 'nice -n 19 sh -c "( ( nohup chown -R ask:ask /www/askapache.com &>/dev/null ) & )"'
Webmaster do AskApache
fonte
8
Sei que essa é uma resposta muito antiga, mas você poderia adicionar alguns comentários sobre por que a maneira entre parênteses é a melhor, qual (se houver) diferença que a adição nohupfaz e por que e quando você usaria nice? Eu acho que isso acrescentaria muito a essa resposta.
Dr K
Talvez para responder parcialmente a isso: com nohup, você não precisa anexar o & ao comando a ser executado.
Cadoiz 17/06/19
21

Se você não conseguir / não conseguir manter a conexão aberta, poderá usar a tela , se tiver os direitos para instalá-la.

user@localhost $ screen -t remote-command
user@localhost $ ssh user@target # now inside of a screen session
user@remotehost $ cd /some/directory; program-to-execute &

Para desanexar a sessão da tela: ctrl-a d

Para listar sessões de tela:

screen -ls

Para anexar novamente uma sessão:

screen -d -r remote-command

Observe que a tela também pode criar vários shells dentro de cada sessão. Um efeito semelhante pode ser alcançado com o tmux .

user@localhost $ tmux
user@localhost $ ssh user@target # now inside of a tmux session
user@remotehost $ cd /some/directory; program-to-execute &

Para desanexar a sessão tmux: ctrl-b d

Para listar sessões de tela:

tmux list-sessions

Para anexar novamente uma sessão:

tmux attach <session number>

A chave de controle padrão do tmux, ' ctrl-b', é um pouco difícil de usar, mas existem vários exemplos de configurações do tmux que acompanham o tmux que você pode tentar.

hometoast
fonte
3
como alguém usaria screenisso?
Quamis
18

Eu só queria mostrar um exemplo de trabalho que você pode cortar e colar:

ssh REMOTE "sh -c \"(nohup sleep 30; touch nohup-exit) > /dev/null &\""
cmcginty
fonte
Muito útil. Obrigado.
Michael Martinez
8

A maneira mais rápida e fácil é usar o comando 'at':

ssh user @ target "agora -f /home/foo.sh"

neil
fonte
2
Essa seria uma ótima solução geral se os atargumentos de linha de comando aceitos fossem aceitos após o tempo e não apenas em um arquivo.
Tyler Collier
3
Você pode simular um arquivo com <<< como em: ssh user @ target "now -f <<< 'my_comnads'"
Nico
6

Acho que você terá que combinar algumas dessas respostas para obter o que deseja. Se você usar nohup em conjunto com o ponto-e-vírgula e agrupar tudo entre aspas, obterá:

ssh user@target "cd /some/directory; nohup myprogram > foo.out 2> foo.err < /dev/null"

o que parece funcionar para mim. Com nohup, você não precisa anexar o & ao comando a ser executado. Além disso, se você não precisar ler nenhuma das saídas do comando, poderá usar

ssh user@target "cd /some/directory; nohup myprogram > /dev/null 2>&1"

para redirecionar toda a saída para / dev / null.


fonte
5

Isso funcionou para mim algumas vezes:

ssh -x remoteServer "cd yourRemoteDir; ./yourRemoteScript.sh </dev/null >/dev/null 2>&1 & " 
fs82
fonte
2

Você pode fazer assim ...

sudo /home/script.sh -opt1 > /tmp/script.out &
user889030
fonte
Perfeito, funciona com uma sessão PuTTY SSH. Eu posso sair e o script continua na máquina. Obrigado.
Sat19
1

Na verdade, sempre que preciso executar um comando em uma máquina remota complicada, gosto de colocar o comando em um script na máquina de destino e apenas executá-lo usando o ssh.

Por exemplo:

# simple_script.sh (located on remote server)

#!/bin/bash

cat /var/log/messages | grep <some value> | awk -F " " '{print $8}'

E então eu apenas executei este comando na máquina de origem:

ssh user@ip "/path/to/simple_script.sh"
PaulT
fonte
0

Eu estava tentando fazer a mesma coisa, mas com a complexidade adicional que eu estava tentando fazer isso a partir do Java. Então, em uma máquina executando java, eu estava tentando executar um script em outra máquina, em segundo plano (com nohup).

Na linha de comando, aqui está o que funcionou: (você pode não precisar do "-i keyFile" se não precisar dele para ssh no host)

ssh -i keyFile user@host bash -c "\"nohup ./script arg1 arg2 > output.txt 2>&1 &\""

Observe que, na minha linha de comando, há um argumento após o "-c", que é todo entre aspas. Mas para que funcione do outro lado, ele ainda precisa das aspas, então eu tive que colocar aspas escapadas dentro dela.

De java, aqui está o que funcionou:

ProcessBuilder b = new ProcessBuilder("ssh", "-i", "keyFile", "bash", "-c",
 "\"nohup ./script arg1 arg2 > output.txt 2>&1 &\"");
Process process = b.start();
// then read from process.getInputStream() and close it.

Demorou um pouco de tentativa e erro para fazer isso funcionar, mas parece funcionar bem agora.

Randy Wilson
fonte
0

Pareceu-me bastante conveniente ter uma sessão remota do tmux usando a tmux new -d <shell cmd>sintaxe como esta:

ssh someone@elsewhere 'tmux new -d sleep 600'

Isso iniciará uma nova sessão no elsewherehost e o comando ssh na máquina local retornará ao shell quase instantaneamente. Você pode então ssh no host remoto e tmux attachnessa sessão. Observe que não há nada sobre o tmux local em execução, apenas remoto!

Além disso, se você deseja que sua sessão persista após a conclusão do trabalho, basta adicionar um iniciador de shell após seu comando, mas não se esqueça de colocar aspas:

ssh someone@elsewhere 'tmux new -d "~/myscript.sh; bash"'
zebrilo
fonte
0
YOUR-COMMAND &> YOUR-LOG.log &    

Isso deve executar o comando e atribuir uma identificação de processo. Você pode simplesmente tail -f YOUR-LOG.log para ver os resultados gravados nele à medida que ocorrem. você pode sair a qualquer momento e o processo continuará

richprice316
fonte
0

Você pode fazer isso sem nohup:

ssh user@host 'myprogram >out.log 2>err.log &'
ijt
fonte
-2

Eu acho que é isso que você precisa: Primeiro você precisa instalar sshpassna sua máquina. então você pode escrever seu próprio script:

while read pass port user ip; do
sshpass -p$pass ssh -p $port $user@$ip <<ENDSSH1
    COMMAND 1
    .
    .
    .
    COMMAND n
ENDSSH1
done <<____HERE
    PASS    PORT    USER    IP
      .      .       .       .
      .      .       .       .
      .      .       .       .
    PASS    PORT    USER    IP    
____HERE
MLSC
fonte
-3

Primeiro, siga este procedimento:

Efetue login em A como usuário a e gere um par de chaves de autenticação. Não digite uma senha:

a@A:~> ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/a/.ssh/id_rsa): 
Created directory '/home/a/.ssh'.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/a/.ssh/id_rsa.
Your public key has been saved in /home/a/.ssh/id_rsa.pub.
The key fingerprint is:
3e:4f:05:79:3a:9f:96:7c:3b:ad:e9:58:37:bc:37:e4 a@A

Agora use ssh para criar um diretório ~ / .ssh como usuário b em B. (O diretório já pode existir, o que é bom):

a@A:~> ssh b@B mkdir -p .ssh
b@B's password: 

Finalmente, adicione a nova chave pública de a em b @ B: .ssh / allowed_keys e digite a senha de b uma última vez:

a@A:~> cat .ssh/id_rsa.pub | ssh b@B 'cat >> .ssh/authorized_keys'
b@B's password: 

A partir de agora, você pode fazer login em B como b e em A como a sem senha:

a@A:~> ssh b@B

então isso funcionará sem digitar uma senha

ssh b @ B "cd / some / directory; programa para executar &"

Kevin Duterne
fonte
1
A questão diz que dagorym já definir as teclas para cima para não exigir uma senha, mas ele ainda está pendurado
Max Nanasy