¿Cómo usar SSH para ejecutar un script de shell en una máquina remota?

Tengo que ejecutar un script de shell (Windows / Linux) en una máquina remota.

Tengo SSH configurado en la máquina A y B. Mi script está en la máquina A, que ejecutará parte de mi código en una máquina remota, la máquina B.

Las computadoras locales y remotas pueden ser sistemas basados ​​en Windows o Unix.

¿Hay alguna forma de ejecutar esto usando plink / ssh?

    Si la máquina A es una caja de Windows, puede usar Plink (parte de PuTTY ) con el parámetro -m, y ejecutará la secuencia de comandos local en el servidor remoto.

    plink root@MachineB -m local_script.sh 

    Si la Máquina A es un sistema basado en Unix, puede usar:

     ssh root@MachineB 'bash -s' < local_script.sh 

    No debería tener que copiar el script al servidor remoto para ejecutarlo.

    Esta es una vieja pregunta, y la respuesta de Jason funciona bien, pero me gustaría añadir esto:

     ssh user@host < <'ENDSSH' #commands to run on remote host ENDSSH 

    Esto también se puede usar con su y comandos que requieren la entrada del usuario. (tenga en cuenta el ' escapado heredoc)

    Editar: Dado que esta respuesta sigue recibiendo bits de tráfico, agregaría aún más información a este maravilloso uso de heredoc:

    Puede anidar comandos con esta syntax, y esa es la única forma en que el anidamiento parece funcionar (de una manera sensata)

     ssh user@host < <'ENDSSH' #commands to run on remote host ssh user@host2 <<'END2' # Another bunch of commands on another host wall <<'ENDWALL' Error: Out of cheese ENDWALL ftp ftp.secureftp-test.com <<'ENDFTP' test test ls ENDFTP END2 ENDSSH 

    En realidad, puedes tener una conversación con algunos servicios como telnet, ftp, etc. Pero recuerda que heredoc simplemente envía el stdin como texto, no espera la respuesta entre líneas

    Editar: Acabo de enterarme de que puedes sangrar el interior si utilizas < <-END ¡ < <-END !

     ssh user@host < <-'ENDSSH' #commands to run on remote host ssh user@host2 <<-'END2' # Another bunch of commands on another host wall <<-'ENDWALL' Error: Out of cheese ENDWALL ftp ftp.secureftp-test.com <<-'ENDFTP' test test ls ENDFTP END2 ENDSSH 

    (Creo que esto debería funcionar)

    También vea http://tldp.org/LDP/abs/html/here-docs.html

    Además, no se olvide de las variables de escape si desea recogerlos desde el host de destino.

    Esto me ha sorprendido en el pasado.

    Por ejemplo:

     user@host> ssh user2@host2 "echo \$HOME" 

    imprime / home / user2

    mientras

     user@host> ssh user2@host2 "echo $HOME" 

    imprime / home / usuario

    Otro ejemplo:

     user@host> ssh user2@host2 "echo hello world | awk '{print \$1}'" 

    imprime “hola” correctamente.

    Esta es una extensión de la respuesta de YarekT para combinar comandos remotos en línea con pasar variables ENV de la máquina local al host remoto para que pueda parametrizar sus scripts en el lado remoto:

     ssh user@host ARG1=$ARG1 ARG2=$ARG2 'bash -s' < <'ENDSSH' # commands to run on remote host echo $ARG1 $ARG2 ENDSSH 

    Encontré esto excepcionalmente útil al mantenerlo todo en una secuencia de comandos por lo que es muy legible y mantenible.

    Por qué esto funciona ssh admite la siguiente syntax:

    ssh user @ host remote_command

    En bash podemos especificar variables de entorno para definir antes de ejecutar un comando en una sola línea, como por ejemplo:

    ENV_VAR_1 = 'value1' ENV_VAR_2 = 'value2' bash -c 'echo $ ENV_VAR_1 $ ENV_VAR_2'

    Eso hace que sea fácil definir variables antes de ejecutar un comando. En este caso, echo es nuestro comando que estamos ejecutando. Todo antes del eco define variables de entorno.

    Así que combinamos esas dos características y la respuesta de YarekT para obtener:

    ssh user @ host ARG1 = $ ARG1 ARG2 = $ ARG2 'bash -s' < < 'ENDSSH' ...

    En este caso, estamos configurando ARG1 y ARG2 a valores locales. Enviando todo después de user @ host como remote_command. Cuando la máquina remota ejecuta el comando ARG1 y ARG2 se establecen los valores locales, gracias a la evaluación de línea de comando local, que define las variables de entorno en el servidor remoto, y luego ejecuta el comando bash -s usando esas variables. Voila.

     $ ssh user@hostB "ls -la" 

    Esto le solicitará una contraseña, a menos que haya copiado la clave pública de su usuario hostA en el archivo authorized_keys en la página de inicio del directorio .ssh del usuario. Eso permitirá la autenticación sin contraseña (si se acepta como un método de autenticación en la configuración del servidor ssh)

    Empecé a usar Fabric para operaciones más sofisticadas. Fabric requiere Python y un par de otras dependencias, pero solo en la máquina cliente. El servidor solo necesita ser un servidor ssh. Encuentro que esta herramienta es mucho más poderosa que los scripts de shell entregados a SSH, y bien vale la pena la molestia de configurarlo (especialmente si disfrutas de la progtwigción en Python). Fabric maneja secuencias de comandos en múltiples hosts (o hosts de ciertos roles), ayuda a facilitar las operaciones idempotentes (como agregar una línea a un script de configuración, pero no si ya está allí), y permite la construcción de lógica más compleja (como el Python) el lenguaje puede proporcionar).

    Suponiendo que quiere decir que quiere hacer esto automáticamente desde una máquina “local”, sin iniciar sesión manualmente en la máquina “remota”, debe buscar en una extensión TCL conocida como Esperar, que está diseñada precisamente para este tipo de situación. La página de inicio a continuación parece un poco asquerosa, pero no dejes que eso te disuada; También proporcioné un enlace a un script para iniciar sesión / interactuar a través de SSH.

    http://expect.nist.gov/

    http://bash.cyberciti.biz/security/expect-ssh-login-script/

    Intenta ejecutar ssh user@remote sh ./script.unx .

    La respuesta aquí ( https://stackoverflow.com/a/2732991/4752883 ) funciona muy bien si está intentando ejecutar un script en una máquina Linux remota utilizando plink o ssh . Funcionará si el script tiene múltiples líneas en linux .

    ** Sin embargo, si está tratando de ejecutar un script por lotes ubicado en una máquina linux/windows local y su máquina remota es Windows , y consiste en varias líneas usando **

    plink root@MachineB -m local_script.bat

    no funcionará

    Solo se ejecutará la primera línea del script. Esta es probablemente una limitación del plink .

    Solución 1:

    Para ejecutar un script por lotes de varias líneas (especialmente si es relativamente simple, que consiste en unas pocas líneas):

    Si su script por lotes original es el siguiente

     cd C:\Users\ipython_user\Desktop python filename.py 

    puede combinar las líneas usando el separador “&&” de la siguiente manera en su archivo local_script.bat : https://stackoverflow.com/a/8055390/4752883 :

     cd C:\Users\ipython_user\Desktop && python filename.py 

    Después de este cambio, puede ejecutar la secuencia de comandos como se señala aquí @ JasonR.Coombs: https://stackoverflow.com/a/2732991/4752883 con:

     `plink root@MachineB -m local_script.bat` 

    Solución 2:

    Si su secuencia de comandos por lotes es relativamente complicada, puede ser mejor utilizar una secuencia de comandos por lotes que encapsule el comando plink, así como la siguiente, tal como lo señala @Martin https://stackoverflow.com/a/32196999/4752883 :

     rem Open tunnel in the background start plink.exe -ssh [username]@[hostname] -L 3307:127.0.0.1:3306 -i "[SSH key]" -N rem Wait a second to let Plink establish the tunnel timeout /t 1 rem Run the task using the tunnel "C:\Program Files\R\R-3.2.1\bin\x64\R.exe" CMD BATCH qidash.R rem Kill the tunnel taskkill /im plink.exe 

    Esta secuencia de comandos bash realiza ssh en una máquina remota de destino y ejecuta algún comando en la máquina remota, no olvide instalar esperar antes de ejecutarlo (en Mac brew install expect )

     #!/usr/bin/expect set username "enterusenamehere" set password "enterpasswordhere" set hosts "enteripaddressofhosthere" spawn ssh $username@$hosts expect "$username@$hosts's password:" send -- "$password\n" expect "$" send -- "somecommand on target remote machine here\n" sleep 5 expect "$" send -- "exit\n" 

    Primero, copie el script en la Máquina B usando scp

    [usuario @ máquinaA] $ scp / ruta / a / script usuario @ máquinaB: / home / usuario / ruta

    Entonces, solo ejecuta el script

    [usuario @ máquinaA] $ usuario ssh @ máquinaB “/ home / usuario / ruta / script”

    Esto funcionará si ha otorgado permisos ejecutables al script.