Come posso eseguire uno script bash locale su macchine remote tramite ssh?


51

Sto cercando un modo per trasferire la configurazione da una macchina centrale a più macchine remote senza la necessità di installare nulla sulle macchine remote.

L'obiettivo è quello di fare qualcosa che potresti trovare con strumenti come cfengine, ma su un set di macchine che non hanno agenti impostati. Questa potrebbe effettivamente essere una buona tecnica di impostazione cfagentsu un set di macchine remote esistenti.



1
Le domande attuali hanno 23 voti in cui il duplicato su SO ha 55: P
MoJo

Risposte:


55

È possibile passare uno script e farlo eseguire in modo effimero eseguendo il piping ed eseguendo una shell.

per esempio

echo "ls -l; echo 'Hello World'" | ssh me@myserver /bin/bash

Naturalmente, la "ls -l; echo 'Hello World'"parte potrebbe essere sostituita con uno script bash memorizzato in un file sul computer locale.

per esempio

cat script.sh | ssh me@myserver /bin/bash

Saluti!


2
Come faccio a farlo funzionare come sudo sul sistema remoto.eg Se fossi collegato al server remoto di solito lo eseguo come sudo -u testuser script.sh
Sharjeel

E se lo script che sto chiamando coinvolge interazioni dell'utente ???
Abhimanyu Srivastava,

20

Ci sono molti modi per farlo.

1:

ssh user@remote_server 'bash -s' < localfile

2:

cat localfile  | ssh user@remote_server

3:

ssh user@remote_server "$(< localfile)"

il numero 3 è il mio modo preferito, consente comandi interattivi ad es su -S service nginx restart

(Il numero 1 consumerà il resto dello script come input per la domanda sulla password quando si utilizza su -S.)


4
Per quanto riguarda l'esecuzione dello script locale sul computer remoto: esiste un modo per inviare la variabile come argomento al computer remoto ...? cioè insieme allo script, voglio inviare una variabile (con più righe) come argomento alla macchina remota. Lo script intende quindi utilizzare la variabile.

13

Consiglierei Fabric di Python per questo scopo:

#!/usr/bin/python
# ~/fabfile.py

from fabric_api import *

env.hosts = ['host1', 'host2']
def deploy_script():
    put('your_script.sh', 'your_script.sh', mode=0755)
    sudo('./your_script.sh')

# from shell
$ fab deploy_script

Dovresti essere in grado di utilizzare quanto sopra per iniziare. Consulta l'eccellente documentazione di Fabric per fare il resto. Come addendum, è assolutamente possibile scrivere interamente lo script all'interno di Fabric - non è necessaria alcuna copia, tuttavia è necessario notare che per modificare lo script su tutte le macchine, è necessario modificare solo la copia locale e ridistribuire. Inoltre, con poco più dell'utilizzo base dell'API, è possibile modificare lo script in base all'host su cui è attualmente in esecuzione e / o ad altre variabili. È una sorta di aspettativa pitonica.


Non penso che questo risponda esattamente alla domanda, ma mi piace l'idea e potrei vedere Fabric come uno strumento utile.
tremoloqui,

1
@tremoloqui Fabric è un wrapper Python attorno a ssh: non è necessario installare nulla sui computer di destinazione, tranne lo script che viene inviato. Che, se riscritto come una serie di comandi Fabric (usando rune sudo), non è nemmeno necessario.
Izkata,

5

Questo è esattamente lo scopo di Ansible. Non esiste alcun agente, devi solo creare un file di testo chiamato:

/etc/ansible/hosts

con contenuti simili a:

[webhosts]
web[1-8]

Ciò specifica che le macchine "web1, web2 ... web8" sono nel gruppo "webhost". Quindi puoi fare cose come:

ansible webhosts -m service -a "name=apache2 state=restarted" --sudo

per riavviare il servizio apache2 su tutti i tuoi computer, usando sudo.

Puoi eseguire comandi al volo come:

ansible webhosts -m shell -a "df -h"

oppure puoi eseguire uno script locale sul computer remoto:

ansible webhosts -m script -a "./script.sh"

oppure puoi creare un playbook (consulta la documentazione per i dettagli) con una configurazione completa a cui desideri che i tuoi server siano conformi e distribuiscilo con:

ansible-playbook webplaybook.yml

Fondamentalmente puoi iniziare a usarlo come strumento da riga di comando per eseguire comandi su più server ed espandere il suo utilizzo in uno strumento di configurazione completo come ritieni opportuno.


3
Mi piace rispondere tanto quanto il prossimo, ma se sta chiedendo una sceneggiatura, Ansible ha un modulo di sceneggiatura davvero carino :ansible webhosts -m script script.sh
ptman,

1
Tutte le altre risposte riguardano uno script bash, ma non è quello che ha chiesto specificamente. Ha appena detto spingendo la configurazione su macchine remote. Ma una buona menzione del modulo di script :)
seumasmac,

Si prega di votare questa risposta! Questo è il modo di farlo!
pulcini,

@ptman Ho appena notato che mentre non menziona una sceneggiatura nella domanda, lo fa nel titolo! Scusate. Ho aggiornato.
seumasmac,

3

Come spiegato in questa risposta puoi usare heredoc :

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

Devi stare attento con heredoc, perché invia solo testo, ma non aspetta davvero la risposta. Ciò significa che non attenderà l'esecuzione dei tuoi comandi.


1

La risposta qui ( https://stackoverflow.com/a/2732991/4752883 ) funziona benissimo se stai cercando di eseguire uno script su una macchina Linux remota usando plinko ssh. Funzionerà se lo script ha più righe linux.

** Tuttavia, se si sta tentando di eseguire uno script batch situato su un linux/windowscomputer locale e il computer remoto lo è Windows, ed è composto da più linee usando **

plink root@MachineB -m local_script.bat

non funzionerà.

Verrà eseguita solo la prima riga dello script. Questo è probabilmente un limite di plink.

Soluzione 1:

Per eseguire uno script batch multilinea (soprattutto se è relativamente semplice, composto da poche righe):

Se lo script batch originale è il seguente

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

puoi unire le linee usando il separatore "&&" come segue nel tuo local_script.batfile come segue https://stackoverflow.com/a/8055390/4752883 :

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

Dopo questa modifica, è quindi possibile eseguire lo script come indicato qui da @ JasonR.Coombs: https://stackoverflow.com/a/2732991/4752883

Soluzione 2:

Se lo script batch è relativamente complicato, potrebbe essere meglio utilizzare uno script batch che incapsuli il comando plink e come indicato qui di seguito da @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

0

Perché non semplicemente copiare prima lo script, quindi eseguirlo?

scp your_script.sh the_server:
ssh the_server "chmod +x your_script.sh; ./your_script.sh"

Ovviamente dovresti stare attento a non caricarlo in un luogo scrivibile dal mondo, quindi nessun altro potrebbe giocherellare con esso prima di eseguirlo (possibilmente come root).


1
Il motivo per cui non voglio caricare lo script è che non deve essere gestito e presenta i rischi che hai citato. Inoltre, mi sembra che sia più semplice del processo in più passaggi di caricamento, elaborazione e (facoltativamente) eliminazione.
tremoloqui,

0

Riscrivere il copione in un modo che ogni comando in essa già è prefissato con ssh e un hostname / IP o un elenco di quali viene passato allo script come argomento (ammesso che abbiate l'autenticazione a chiave ssh-agent senza password / impostato). Potrebbe essere necessario qualche lavoro per restituire correttamente i codici di errore / ritorno dai comandi remoti ....


0

Se lo script non è troppo grande e stai usando bash o ksh ...

ssh vm24 -t bash -c "$(printf "%q" "$(< shell-test.sh )")"

Sia stdin che stdout funzionano correttamente ma lo script è limitato alla dimensione dell'argomento (di solito circa 100k). Gli argomenti alla sceneggiatura possono funzionare, alla fine della riga, eventualmente seguendo un argomento "-" aggiuntivo. Il "-t" per allocare un pty è facoltativo.

Attenzione: questo confonde il completamento bash, non premere il tasto.

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.