Conseguir que ssh ejecute un comando en segundo plano en la máquina de destino

304

Esta es una pregunta complementaria a ¿Cómo se usa ssh en un script de shell? pregunta. Si quiero ejecutar un comando en la máquina remota que se ejecuta en segundo plano en esa máquina, ¿cómo consigo que regrese el comando ssh? Cuando trato de incluir el ampersand (&) al final del comando, simplemente se cuelga. La forma exacta del comando se ve así:

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

¿Algunas ideas? Una cosa a tener en cuenta es que los inicios de sesión en la máquina de destino siempre producen un banner de texto y tengo claves SSH configuradas, por lo que no se requiere contraseña.

dagorym
fuente

Respuestas:

315

Tuve este problema en un programa que escribí hace un año; resulta que la respuesta es bastante complicada. Necesitará usar nohup así como la redirección de salida, como se explica en el artículo de wikipedia sobre nohup , copiado aquí para su conveniencia.

Nohuping trabajos en segundo plano, por ejemplo, es útil cuando se inicia sesión a través de SSH, ya que los trabajos en segundo plano pueden hacer que el shell se bloquee al cerrar sesión debido a una condición de carrera [2]. Este problema también se puede superar redirigiendo las tres secuencias de E / S:

nohup myprogram > foo.out 2> foo.err < /dev/null &
Jax
fuente
1
Esos archivos se crean en el directorio actual. Entonces, el límite es la cantidad de espacio libre en la partición. Por supuesto, también puede redirigir a /dev/null.
Frank Kusters
2
¿Alguna idea sobre el fondo del proceso una vez que haya terminado de solicitar indicaciones? (como un gpg --decrypt que terminó de pedir la contraseña)
isaaclw
Intentando iniciar un trabajador de búsqueda en segundo plano usando nohup, pero no funciona .. :(
Infant Dev
1
¿Puedes explicar qué < /dev/nullsignifica? Gracias.
Qian Chen
1
También del artículo de wikipedia sobre nohup: "También tenga en cuenta que una sesión SSH de cierre no siempre envía una señal HUP a procesos dependientes. Entre otros, esto depende de si se asignó un pseudo-terminal o no". Entonces, aunque estrictamente no siempre se necesite el nohup, es mejor a largo plazo con él que sin él.
Jax
254

Esta ha sido la forma más limpia de hacerlo por mí:

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

Lo único que se ejecuta después de esto es el comando real en la máquina remota

Russ
fuente
77
-nno es necesario como -fimplica-n
blissini
66
ssh -fdeja el proceso ssh conectado, solo en segundo plano. Las soluciones / dev / null permiten que ssh se desconecte rápidamente, lo que podría ser preferible.
Beni Cherniavsky-Paskin
Esta solución también funciona para enviar comandos a través de ssh a un NAS de Syonology
Stefan F
Necesito los resultados de "ls -l" para que aparezcan en mi control remoto, este comando no lo hace.
Siddharth
@Siddharth Luego redirige a algún archivo con nombre en lugar de / dev / null.
Sherrellbc
29

Redirigir fd's

La salida debe ser redirigida con lo &>/dev/nullque redirige stderr y stdout a / dev / null y es sinónimo de >/dev/null 2>/dev/nullo >/dev/null 2>&1.

Paréntesis

La mejor manera es usar sh -c '( ( command ) & )'donde el comando sea cualquier cosa.

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

Nohup Shell

También puede usar nohup directamente para iniciar el shell:

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

Buen lanzamiento

Otro truco es usar nice para iniciar el comando / shell:

ssh askapache 'nice -n 19 sh -c "( ( nohup chown -R ask:ask /www/askapache.com &>/dev/null ) & )"'
AskApache Webmaster
fuente
8
Sé que esta es una respuesta muy antigua suya, pero ¿podría agregar algunos comentarios sobre por qué la forma de paréntesis es la mejor manera, qué (si alguna) diferencia agrega nohup, y por qué y cuándo usaría nice? Creo que eso agregaría mucho a esta respuesta.
Dr K
Tal vez para responder parcialmente a esto: con nohup, no necesita agregar el & al comando para ejecutarse.
Cadoiz
21

Si no puede / no puede mantener la conexión abierta, puede usar la pantalla , si tiene los derechos para instalarla.

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 separar la sesión de pantalla: ctrl-a d

Para enumerar sesiones de pantalla:

screen -ls

Para volver a adjuntar una sesión:

screen -d -r remote-command

Tenga en cuenta que la pantalla también puede crear múltiples shells dentro de cada sesión. Se puede lograr un efecto similar con tmux .

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

Para separar la sesión de tmux: ctrl-b d

Para enumerar sesiones de pantalla:

tmux list-sessions

Para volver a adjuntar una sesión:

tmux attach <session number>

La clave de control predeterminada de tmux, ' ctrl-b', es algo difícil de usar, pero hay varios ejemplos de configuraciones de tmux que se envían con tmux que puede probar.

tostada casera
fuente
3
¿Cómo se usaría screenpara esto?
Quamis
18

Solo quería mostrar un ejemplo de trabajo que puede cortar y pegar:

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

La forma más rápida y fácil es usar el comando 'at':

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

neil
fuente
2
Esta sería una gran solución general si se ataceptan argumentos de línea de comandos después del tiempo y no solo de un archivo.
Tyler Collier
3
Puede simular un archivo con <<< como en: ssh user @ target "at now -f <<< 'my_comnads'"
Nico
6

Creo que tendrá que combinar un par de estas respuestas para obtener lo que desea. Si usa nohup junto con el punto y coma, y ​​envuelve todo entre comillas, obtendrá:

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

lo que parece funcionar para mí Con nohup, no necesita agregar el & al comando para ejecutarse. Además, si no necesita leer ninguno de los resultados del comando, puede usar

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

para redirigir toda la salida a / dev / null.


fuente
5

Esto funcionó para mí muchas veces:

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

Puedes hacerlo así ...

sudo /home/script.sh -opt1 > /tmp/script.out &
usuario889030
fuente
Perfecto, funciona con una sesión PuTTY SSH. Puedo salir y el script continúa en la máquina. Gracias.
Satria
1

En realidad, cada vez que necesito ejecutar un comando en una máquina remota que es complicado, me gusta poner el comando en un script en la máquina de destino, y simplemente ejecutar ese script usando ssh.

Por ejemplo:

# simple_script.sh (located on remote server)

#!/bin/bash

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

Y luego ejecuto este comando en la máquina de origen:

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

Intentaba hacer lo mismo, pero con la complejidad añadida que intentaba hacerlo desde Java. Entonces, en una máquina que ejecutaba Java, estaba tratando de ejecutar un script en otra máquina, en segundo plano (con nohup).

Desde la línea de comandos, esto es lo que funcionó: (es posible que no necesite el "-i keyFile" si no lo necesita para enviar ssh al host)

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

Tenga en cuenta que para mi línea de comando, hay un argumento después de "-c", que está todo entre comillas. Pero para que funcione en el otro extremo, todavía necesita las comillas, así que tuve que ponerle comillas escapadas.

De java, esto es lo que funcionó:

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.

Tomó un poco de prueba y error para que esto funcionara, pero parece funcionar bien ahora.

Randy Wilson
fuente
0

Me pareció bastante conveniente tener una sesión tmux remota usando la tmux new -d <shell cmd>sintaxis como esta:

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

Esto lanzará una nueva sesión en el elsewherehost y el comando ssh en la máquina local volverá al shell casi instantáneamente. Luego puede enviar ssh al host remoto y tmux attacha esa sesión. Tenga en cuenta que no hay nada acerca de la ejecución local de tmux, ¡solo remota!

Además, si desea que su sesión persista después de finalizar el trabajo, simplemente agregue un iniciador de shell después de su comando, pero no olvide incluir comillas:

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

Esto debería ejecutar el comando y asignar una identificación de proceso que puede simplemente seguir -f YOUR-LOG.log para ver los resultados escritos a medida que ocurren. puede cerrar sesión en cualquier momento y el proceso continuará

richprice316
fuente
0

Puedes hacer esto sin nohup:

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

Creo que esto es lo que necesita: al principio, debe instalarlo sshpassen su máquina. entonces puedes escribir tu propio 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
fuente
-3

Primero siga este procedimiento:

Inicie sesión en A como usuario ay genere un par de claves de autenticación. No ingrese una frase de contraseña:

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

Ahora use ssh para crear un directorio ~ / .ssh como usuario b en B. (El directorio ya puede existir, lo cual está bien):

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

Finalmente, agregue la nueva clave pública de a a b @ B: .ssh / Authorized_keys e ingrese la contraseña de b por última vez:

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

A partir de ahora puede iniciar sesión en B como b desde A como a sin contraseña:

a@A:~> ssh b@B

entonces esto funcionará sin ingresar una contraseña

ssh b @ B "directorio cd / some /; programa para ejecutar &"

Kevin Duterne
fuente
1
La pregunta dice que dagorym ya configuró las claves para que no requieran una contraseña, pero todavía está colgando
Max Nanasy