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

Esta es una pregunta de seguimiento al ¿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 puedo obtener el comando ssh para regresar? Cuando trato de simplemente incluir el signo & (&) al final del comando, simplemente 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 las claves SSH configuradas por lo que no se requiere contraseña.

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

Nohuping backgrounded jobs es, por ejemplo, útil cuando se inicia sesión a través de SSH, ya que los trabajos en segundo plano pueden provocar que el shell suspenda el cierre de sesión debido a una condición de carrera [2]. Este problema también se puede solucionar redirigiendo las tres transmisiones de E / S:

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

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

Redirigir fd’s

La salida debe redirigirse con &>/dev/null que redirige a stderr y stdout a / dev / null y es un sinónimo de >/dev/null 2>/dev/null o >/dev/null 2>&1 .

Parantheses

La mejor manera es usar sh -c '( ( command ) & )' donde el comando es 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 lanzar el comando / shell:

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

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

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

Si no puede / no puede mantener la conexión abierta, podría 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 las sesiones de pantalla:

 screen -ls 

Para volver a conectar 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 las sesiones de pantalla:

 tmux list-sessions 

Para volver a conectar una sesión:

 tmux attach  

La clave de control predeterminada de tmux, ‘ ctrl-b ‘, es un tanto difícil de usar, pero hay varias configuraciones tmux de ejemplo que se incluyen con tmux que puede probar.

Creo que deberás combinar un par de estas respuestas para obtener lo que quieres. Si usas nohup junto con el punto y coma, y ​​envuelves todo entre comillas, obtienes:

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

que parece funcionar para mí Con nohup, no necesita agregar el & al comando para ejecutar. Además, si no necesita leer ninguna de las salidas del comando, puede usar

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

redirigir toda la salida a / dev / null.

La forma más rápida y sencilla es usar el comando ‘at’:

usuario ssh @ target “en este momento -f /home/foo.sh”

Esto funcionó para mí puede veces:

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

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

Por ejemplo:

 # simple_script.sh (located on remote server) #!/bin/bash cat /var/log/messages | grep  | awk -F " " '{print $8}' 

Y luego solo ejecuto este comando en la máquina fuente:

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

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

Desde la línea de comandos, esto es lo que funcionó: (es posible que no necesites el “-i keyFile” si no lo necesitas para 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 la “-c”, que está entre comillas. Pero para que funcione en el otro extremo, todavía necesita las comillas, así que tuve que poner citas escapadas dentro de ella.

Desde 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 funcione, pero parece funcionar bien ahora.

Primero siga este procedimiento:

Inicie sesión en A como usuario a y 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 sin contraseña:

 a@A:~> ssh b@B 

entonces esto funcionará sin ingresar una contraseña

ssh b @ B “cd / some / directorio; progtwig-para-ejecutar y”

Creo que esto es lo que necesita: Al principio necesita instalar sshpass en su máquina. entonces puedes escribir tu propia secuencia de comandos:

 while read pass port user ip; do sshpass -p$pass ssh -p $port $user@$ip <