web-dev-qa-db-fra.com

Comment utiliser SSH pour exécuter un script Shell sur une machine distante?

Je dois exécuter un script Shell (Windows/Linux) sur une machine distante.

SSH est configuré sur les machines A et B. Mon script est sur la machine A qui exécutera une partie de mon code sur une machine distante, la machine B.

Les ordinateurs locaux et distants peuvent être des systèmes Windows ou Unix.

Existe-t-il un moyen de faire cela en utilisant plink/ssh?

1136
Arun

Si la machine A est une boîte Windows, vous pouvez utiliser Plink (une partie de PuTTY ) avec le paramètre -m et exécuter le script local sur le serveur distant.

plink root@MachineB -m local_script.sh

Si la machine A est un système Unix, vous pouvez utiliser:

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

Vous ne devriez pas avoir à copier le script sur le serveur distant pour l'exécuter.

1119
Jason R. Coombs

C'est une vieille question, et la réponse de Jason fonctionne très bien, mais j'aimerais ajouter ceci:

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

Ceci peut également être utilisé avec les commandes su et qui nécessitent une entrée de l'utilisateur. (notez le ' échappé à Heredoc)

Edit: Depuis que cette réponse continue à recevoir des morceaux de trafic, je voudrais ajouter encore plus d'informations à cette utilisation merveilleuse de heredoc:

Vous pouvez imbriquer des commandes avec cette syntaxe, et c’est la seule façon dont l’emboîtement semble fonctionner (de manière saine).

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

Vous pouvez en fait avoir une conversation avec certains services tels que telnet, ftp, etc. Mais rappelez-vous qu'heredoc envoie simplement le stdin sous forme de texte, il n'attend pas de réponse entre les lignes

Edit: Je viens de découvrir que vous pouvez indenter l’intérieur avec des onglets si vous utilisez <<-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

(Je pense que cela devrait fonctionner)

Voir aussi http://tldp.org/LDP/abs/html/here-docs.html

569
Yarek T

En outre, n'oubliez pas d'échapper aux variables si vous souhaitez les récupérer à partir de l'hôte de destination.

Cela m'a surpris dans le passé.

Par exemple:

user@Host> ssh user2@Host2 "echo \$HOME"

imprime/home/utilisateur2

tandis que

user@Host> ssh user2@Host2 "echo $HOME"

imprime/home/utilisateur

Un autre exemple:

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

affiche "bonjour" correctement.

235
dogbane

Ceci est une extension de la réponse de YarekT consistant à combiner des commandes distantes en ligne avec la transmission de variables ENV de la machine locale à l'hôte distant afin que vous puissiez paramétrer vos scripts du côté distant:

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

J'ai trouvé cela extrêmement utile en conservant tout cela dans un seul script, ce qui le rend très lisible et facile à gérer.

Pourquoi ça marche ssh supporte la syntaxe suivante:

ssh utilisateur @ hôte remote_command

Dans bash, nous pouvons spécifier les variables d'environnement à définir avant d'exécuter une commande sur une seule ligne, comme ceci:

ENV_VAR_1 = 'valeur1' ENV_VAR_2 = 'valeur2' bash -c 'echo $ ENV_VAR_1 $ ENV_VAR_2'

Cela facilite la définition des variables avant d'exécuter une commande. Dans ce cas, echo est notre commande que nous exécutons. Tout ce qui avant écho définit les variables d'environnement.

Nous combinons donc ces deux fonctionnalités avec la réponse de YarekT pour obtenir:

ssh utilisateur @ hôte ARG1 = $ ARG1 ARG2 = $ ARG2 'bash -s' << 'ENDSSH' ...

Dans ce cas, nous définissons ARG1 et ARG2 sur des valeurs locales. Envoi de tout après l'utilisateur @ Host en tant que remote_command. Lorsque la machine distante exécute la commande ARG1 et ARG2, les valeurs locales sont définies, grâce à l'évaluation en ligne de commande locale, qui définit les variables d'environnement sur le serveur distant, puis exécute la commande bash -s à l'aide de ces variables. Voila.

144
chubbsondubs
<hostA_Shell_Prompt>$ ssh user@hostB "ls -la"

Cela vous demandera un mot de passe, à moins que vous n'ayez copié la clé publique de votre utilisateur hostA dans le fichier allowed_keys sur le répertoire principal de l'utilisateur .ssh. Cela permettra une authentification sans mot de passe (si accepté comme méthode d'authentification sur la configuration du serveur ssh)

100
Vinko Vrsalovic

J'ai commencé à utiliser Fabric pour des opérations plus sophistiquées. Fabric nécessite Python et quelques autres dépendances, mais uniquement sur la machine cliente. Le serveur doit seulement être un serveur ssh. Je trouve que cet outil est beaucoup plus puissant que les scripts Shell transmis à SSH et qu'il vaut vraiment la peine de le configurer (en particulier si vous aimez programmer en Python). Fabric gère les scripts en cours d'exécution sur plusieurs hôtes (ou hôtes de certains rôles), facilite les opérations idempotentes (telles que l'ajout d'une ligne à un script de configuration, mais pas si elle existe déjà), et permet la construction d'une logique plus complexe (telle que la Python peut être fourni par le langage).

27
Jason R. Coombs

Essayez de lancer ssh user@remote sh ./script.unx.

10
Jeremy

En supposant que vous vouliez faire cela automatiquement depuis une machine "locale", sans vous connecter manuellement à la machine "distante", vous devriez vous pencher sur une extension TCL appelée Expect, elle est conçue précisément pour ce type de situation. J'ai également fourni un lien vers un script pour la connexion/interaction via SSH.

https://www.nist.gov/services-resources/software/expect

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

9
George Jempty

J'utilise celui-ci pour exécuter un script Shell sur une machine distante (testé sur/bin/bash):

ssh deploy@Host . /home/deploy/path/to/script.sh
3
Is Ma

si vous voulez exécuter une commande comme celle-ci, la commande temp=`ls -a` echo $temp dans `` provoquera des erreurs.

la commande ci-dessous résoudra ce problème ssh user@Host ''' temp=`ls -a` echo $temp '''

2
Jinmiao Luo

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 à l'aide de plink ou ssh. Cela fonctionnera si le script a plusieurs lignes sur linux.

** Cependant, si vous essayez d'exécuter un script batch situé sur une machine locale linux/windows et que votre machine distante est Windows, elle est composée de plusieurs lignes utilisant **

plink root@MachineB -m local_script.bat

ne travaillera pas.

Seule la première ligne du script sera exécutée. C'est probablement une limitation de plink.

Solution 1:

Pour exécuter un script de commandes multiligne (en particulier s'il est relativement simple et composé de quelques lignes):

Si votre script de lot d'origine est comme suit

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

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

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

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

`plink root@MachineB -m local_script.bat`

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 le suit, 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
cat ./script.sh | ssh <user>@<Host>
0
Amir

Ce script bash fait ssh sur une machine distante cible et exécute une commande sur la machine distante. N'oubliez pas d'installer normalement avant de l'exécuter (sur 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"
0
Mohammed Rafeeq
ssh user@hostname ".~/.bashrc;/cd path-to-file/;.filename.sh"

il est fortement recommandé de créer le fichier d’environnement (.bashrc/.bashprofile/.profile). avant d'exécuter quelque chose sur l'hôte distant, car les variables d'environnement des hôtes cible et source peuvent être différentes.

0
Ankush Sahu