Ottenere ssh per eseguire un comando in background sul computer di destinazione


304

Questa è una domanda successiva a Come si usa ssh in uno script di shell? domanda. Se voglio eseguire un comando sul computer remoto che viene eseguito in background su quel computer, come posso ottenere il comando ssh per tornare? Quando provo a includere solo la e commerciale (&) alla fine del comando, si blocca. La forma esatta del comando è simile alla seguente:

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

Qualche idea? Una cosa da notare è che gli accessi al computer di destinazione producono sempre un banner di testo e ho le chiavi SSH impostate, quindi non è richiesta alcuna password.

Risposte:


315

Ho avuto questo problema in un programma che ho scritto un anno fa - risulta che la risposta è piuttosto complicata. Dovrai usare nohup e il reindirizzamento dell'output, come spiegato nell'articolo di Wikipedia su nohup , copiato qui per tua comodità.

Il nohuping di processi in background è utile ad esempio quando si accede tramite SSH, poiché i processi in background possono causare il blocco della shell al logout a causa di una condizione di competizione [2]. Questo problema può essere superato anche reindirizzando tutti e tre i flussi I / O:

nohup myprogram > foo.out 2> foo.err < /dev/null &

1
Tali file vengono creati nella directory corrente. Quindi il limite è la quantità di spazio libero sulla partizione. Ovviamente puoi anche reindirizzare a /dev/null.
Frank Kusters,

2
Qualche idea su come fondare il processo dopo che ha finito per chiedere istruzioni? (come un gpg --decrypt che ha finito per chiedere la password)
isaaclw

Cercando di avviare un lavoratore resque in background usando nohup, ma non funziona .. :(
Infant Dev

1
Puoi spiegare cosa < /dev/nullsignifica? Grazie.
Qian Chen,

1
Anche dall'articolo di Wikipedia su nohup: "Nota anche che una sessione SSH di chiusura non invia sempre un segnale HUP a processi dipendenti. Tra l'altro, questo dipende dal fatto che uno pseudo-terminale sia stato allocato o meno". Quindi, mentre il nohup potrebbe non essere sempre necessario, sei meglio a lungo termine che senza.
Jax

254

Questo è stato il modo più pulito per farlo per me: -

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

L'unica cosa in esecuzione dopo questo è il comando effettivo sul computer remoto


7
-nnon è necessario come -fimplica-n
blissini

6
ssh -flascia il processo ssh collegato, appena in background. Le soluzioni / dev / null consentono a ssh di disconnettersi rapidamente, il che potrebbe essere preferibile.
Beni Cherniavsky-Paskin,

Questa soluzione funziona anche per inviare comandi via SSH a un NAS Syonology
Stefan F,

Ho bisogno dei risultati di "ls -l" da mostrare sul mio telecomando, questo comando non lo fa.
Siddharth,

@Siddharth Quindi reindirizzare a un file denominato anziché / dev / null.
Sherrellbc,

29

Reindirizzamento di fd

L'output deve essere reindirizzato con il &>/dev/nullquale reindirizza sia stderr che stdout a / dev / null ed è sinonimo di >/dev/null 2>/dev/nullo >/dev/null 2>&1.

parantheses

Il modo migliore è usare sh -c '( ( command ) & )'dove comando è qualsiasi cosa.

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

Nohup Shell

Puoi anche usare nohup direttamente per avviare la shell:

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

Bel lancio

Un altro trucco è usare Nice per lanciare il comando / shell:

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

8
So che questa è una tua vecchia risposta, ma potresti aggiungere alcuni commenti sul perché il modo tra parentesi è il modo migliore, quale (se del caso) differenza nohupfa l' aggiunta , e perché e quando useresti nice? Penso che aggiungerebbe molto a questa risposta.
Dott. K

Forse per rispondere parzialmente a questo: con nohup, non è necessario aggiungere & al comando per essere eseguito.
Cadoiz,

21

Se non riesci / non riesci a mantenere aperta la connessione, puoi utilizzare lo schermo , se disponi dei diritti per installarla.

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 &

Per staccare la sessione dello schermo: ctrl-a d

Per elencare le sessioni dello schermo:

screen -ls

Per ricollegare una sessione:

screen -d -r remote-command

Nota che lo schermo può anche creare più shell all'interno di ogni sessione. Un effetto simile può essere ottenuto con tmux .

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

Per staccare la sessione tmux: ctrl-b d

Per elencare le sessioni dello schermo:

tmux list-sessions

Per ricollegare una sessione:

tmux attach <session number>

La chiave di controllo predefinita di tmux, ' ctrl-b', è in qualche modo difficile da usare, ma ci sono molti esempi di configurazioni tmux fornite con tmux che puoi provare.


3
come si usa screenper questo?
Quamis,

18

Volevo solo mostrare un esempio funzionante che puoi tagliare e incollare:

ssh REMOTE "sh -c \"(nohup sleep 30; touch nohup-exit) > /dev/null &\""

Molto utile. Grazie.
Michael Martinez,

8

Il modo più rapido e semplice è usare il comando 'at':

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


2
Questa sarebbe un'ottima soluzione generale se ataccettasse argomenti da riga di comando dopo il tempo e non solo da un file.
Tyler Collier,

3
Puoi simulare un file con <<< come in: ssh user @ target "at now -f <<< 'my_comnads'"
Nico

6

Penso che dovrai combinare un paio di queste risposte per ottenere quello che vuoi. Se usi nohup insieme al punto e virgola e racchiudi il tutto tra virgolette, otterrai:

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

che sembra funzionare per me. Con nohup, non è necessario aggiungere & al comando per essere eseguito. Inoltre, se non è necessario leggere alcun risultato del comando, è possibile utilizzare

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

per reindirizzare tutto l'output su / dev / null.


5

Questo ha funzionato per me volte:

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

2

Puoi farlo in questo modo ...

sudo /home/script.sh -opt1 > /tmp/script.out &

Perfetto, funziona con una sessione SSH PuTTY. Posso uscire e lo script continua sulla macchina. Grazie.
Satria,

1

In realtà, ogni volta che ho bisogno di eseguire un comando su una macchina remota che è complicato, mi piace mettere il comando in uno script sulla macchina di destinazione, ed eseguirlo semplicemente usando ssh.

Per esempio:

# simple_script.sh (located on remote server)

#!/bin/bash

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

E poi ho appena eseguito questo comando sul computer di origine:

ssh user@ip "/path/to/simple_script.sh"

0

Stavo cercando di fare la stessa cosa, ma con l'ulteriore complessità che stavo provando a fare da Java. Quindi su una macchina che eseguiva Java, stavo cercando di eseguire uno script su un'altra macchina, in background (senza nohup).

Dalla riga di comando, ecco cosa ha funzionato: (potrebbe non essere necessario "-i keyFile" se non è necessario per ssh per l'host)

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

Nota che per la mia riga di comando, c'è un argomento dopo "-c", che è tutto tra virgolette. Ma perché funzioni dall'altra parte, ha ancora bisogno delle virgolette, quindi ho dovuto inserire delle virgolette al suo interno.

Da java, ecco cosa ha funzionato:

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.

Ci sono voluti un po 'di tentativi ed errori per farlo funzionare, ma ora sembra funzionare bene.


0

Mi è sembrato abbastanza conveniente avere una sessione tmux remota usando la tmux new -d <shell cmd>sintassi in questo modo:

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

Questo avvierà una nuova sessione elsewheresull'host e il comando ssh sul computer locale tornerà alla shell quasi istantaneamente. È quindi possibile inviare ssh all'host remoto e tmux attacha quella sessione. Nota che non c'è nulla sul funzionamento di tmux locale, solo remoto!

Inoltre, se si desidera che la sessione persista al termine del lavoro, è sufficiente aggiungere un lanciatore shell dopo il comando, ma non dimenticare di racchiuderlo tra virgolette:

ssh someone@elsewhere 'tmux new -d "~/myscript.sh; bash"'

0
YOUR-COMMAND &> YOUR-LOG.log &    

Questo dovrebbe eseguire il comando e assegnare un ID di processo che puoi semplicemente tail -f YOUR-LOG.log per vedere i risultati scritti su di esso mentre accadono. puoi disconnetterti in qualsiasi momento e il processo proseguirà


0

Puoi farlo senza nohup:

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

-2

Penso che questo sia ciò di cui hai bisogno: all'inizio devi installare sshpasssulla tua macchina. quindi puoi scrivere il tuo 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

-3

Per prima cosa segui questa procedura:

Accedi a A come utente a e genera una coppia di chiavi di autenticazione. Non inserire una passphrase:

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

Ora usa ssh per creare una directory ~ / .ssh come utente b su B. (La directory potrebbe già esistere, il che va bene):

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

Infine aggiungi la nuova chiave pubblica di a b @ B: .ssh / authorized_keys e inserisci la password di b un'ultima volta:

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

D'ora in poi puoi accedere a B come b da A come a senza password:

a@A:~> ssh b@B

quindi funzionerà senza inserire una password

ssh b @ B "cd / some / directory; programma da eseguire &"


1
La domanda dice che dagorym ha già impostato le chiavi per non richiedere una password, ma è ancora in sospeso
Max Nanasy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.