web-dev-qa-db-fra.com

Comment exécuter un script bash local sur des machines distantes via ssh?

Je cherche un moyen de pousser la configuration d'une machine centrale vers plusieurs machines distantes sans avoir besoin d'installer quoi que ce soit sur les machines distantes.

Le but est de faire quelque chose comme vous le feriez avec des outils comme cfengine, mais sur un ensemble de machines sur lesquelles aucun agent n'est configuré. Cela pourrait en fait être une bonne technique de configuration de cfagent sur un ensemble de machines distantes existantes.

51
tremoloqui

Vous pouvez passer un script et le faire exécuter de manière éphémère en le canalisant et en exécutant un Shell.

par exemple.

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

Naturellement, le "ls -l; echo 'Hello World'" la partie pourrait être remplacée par un script bash stocké dans un fichier sur la machine locale.

par exemple.

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

À votre santé!

55
tremoloqui

Il y a plusieurs façons de procéder.

1:

ssh user@remote_server 'bash -s' < localfile

2:

cat localfile  | ssh user@remote_server

3:

ssh user@remote_server "$(< localfile)"

le numéro 3 est ma façon préférée, il permet des commandes interactives, par exemple su -S service nginx restart

(# 1 consommera le reste du script comme entrée pour la question de mot de passe lorsque vous utilisez su -S.)

21
Paul Verschoor

Je recommanderais le tissu python à cet effet:

#!/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

Vous devriez pouvoir utiliser ce qui précède pour commencer. Consultez l'excellente documentation de Fabric pour faire le reste. En complément, il est totalement possible d'écrire votre script entièrement dans Fabric - aucune copie n'est nécessaire, mais il convient de noter que pour modifier le script sur toutes les machines, il vous suffira de modifier la copie locale et de la redéployer. De plus, avec un peu plus que l'utilisation de base de l'API, vous pouvez modifier le script en fonction de l'hôte sur lequel il s'exécute actuellement et/ou d'autres variables. C'est une sorte de Pythonic Expect.

13
Sam Halicke

C'est exactement pour cela qu'Ansible est utilisé. Il n'y a pas d'agent, il suffit de créer un fichier texte appelé:

/etc/ansible/hosts

avec un contenu qui ressemble à:

[webhosts]
web[1-8]

Cela spécifierait que les machines "web1, web2 ... web8" sont dans le groupe "webhosts". Ensuite, vous pouvez faire des choses comme:

ansible webhosts -m service -a "name=Apache2 state=restarted" --Sudo

pour redémarrer le service Apache2 sur toutes vos machines, en utilisant Sudo.

Vous pouvez faire des commandes à la volée comme:

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

ou vous pouvez exécuter un script local sur la machine distante:

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

ou vous pouvez créer un playbook (consultez la documentation pour plus de détails) avec une configuration complète à laquelle vous souhaitez que vos serveurs se conforment et le déployer avec:

ansible-playbook webplaybook.yml

Fondamentalement, vous pouvez commencer à l'utiliser comme outil de ligne de commande pour exécuter des commandes sur plusieurs serveurs et étendre son utilisation dans un outil de configuration complet comme bon vous semble.

5
seumasmac

Comme expliqué dans cette réponse vous pouvez utiliser heredoc :

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

Vous devez être prudent avec heredoc, car il envoie simplement du texte, mais il n'attend pas vraiment la réponse. Cela signifie qu'il n'attendra pas que vos commandes soient exécutées.

3
BЈовић

La réponse ici ( https://stackoverflow.com/a/2732991/475288 ) fonctionne très bien si vous essayez d'exécuter un script sur une machine Linux distante en utilisant plink ou ssh. Cela fonctionnera si le script a plusieurs lignes sur linux.

** Cependant, si vous essayez d'exécuter un script de commandes situé sur un linux/windows machine et votre machine distante est Windows, et elle se compose de plusieurs lignes utilisant **

plink root@MachineB -m local_script.bat

ça ne marchera pas.

Seule la première ligne du script sera exécutée. Il s'agit probablement d'une limitation de plink.

Solution 1:

Pour exécuter un script batch multiligne (surtout s'il est relativement simple, composé de quelques lignes):

Si votre script de commandes d'origine est le suivant

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

vous pouvez combiner les lignes en utilisant le séparateur "&&" comme suit dans votre local_script.bat fichier comme suit https://stackoverflow.com/a/8055390/475288 :

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

Après cette modification, vous pouvez ensuite exécuter le script comme indiqué ici par @ JasonR.Coombs: https://stackoverflow.com/a/2732991/475288

Solution 2:

Si votre script de traitement par lots est relativement compliqué, il peut être préférable d'utiliser un script de traitement par lots qui encapsule la commande plink ainsi que comme indiqué ici par @Martin https://stackoverflow.com/a/32196999/475288 :

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
1
alpha_989

Réécrivez le script de manière à ce que chaque commande qu'il contient déjà est préfixée par ssh et un nom d'hôte/ip ou une liste de ceux-ci soit passée au script comme argument (en supposant que vous ayez la clé sans mot de passe/ssh-agent authentification configurée). Certains travaux peuvent être nécessaires pour transmettre correctement les codes d'erreur/retour à partir des commandes à distance ....

0
rackandboneman

Pourquoi ne pas simplement copier le script d'abord, puis l'exécuter?

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

Bien sûr, vous devez faire attention à ne pas le télécharger dans un endroit accessible en écriture, afin que personne d'autre ne puisse le manipuler avant de l'exécuter (éventuellement en tant que root).

0
Dave Vogt

Si le script n'est pas trop gros et que vous utilisez bash ou ksh ...

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

Stdin et stdout fonctionnent correctement, mais le script est limité à la taille de l'argument (généralement environ 100 Ko). Les arguments du script peuvent fonctionner, à la fin de la ligne, en suivant éventuellement un argument "-" supplémentaire. Le "-t" pour allouer un pty est facultatif.

Attention: cela confond la complétion de bash, ne touchez pas tab.

0
user3710044