web-dev-qa-db-fra.com

Quel est le moyen le plus propre de ssh et d'exécuter plusieurs commandes dans Bash?

J'ai déjà un agent ssh configuré et je peux exécuter des commandes sur un serveur externe en script Bash en effectuant des tâches telles que:

ssh blah_server "ls; pwd;"

Maintenant, ce que j'aimerais vraiment faire, c'est d'exécuter de nombreuses commandes longues sur un serveur externe. Enfermer tout cela entre des guillemets serait assez moche, et je préférerais vraiment éviter de répéter plusieurs fois pour éviter cela. 

Alors, y a-t-il un moyen de le faire en une seule fois entre parenthèses ou quelque chose? Je cherche quelque chose comme:

ssh blah_server (
   ls some_folder;
   ./someaction.sh;
   pwd;
)

Fondamentalement, je serai heureux avec toute solution tant qu'elle est propre.

Modifier

Pour clarifier, je parle de cela faisant partie d'un script plus large bash. D'autres personnes pourraient avoir besoin de manipuler le script sur toute la ligne, j'aimerais donc le garder propre. Je ne veux pas avoir un script bash avec une ligne qui ressemble à:

ssh blah_server "ls some_folder; ./someaction.sh 'some params'; pwd; ./some_other_action 'other params';"

parce que c'est extrêmement laid et difficile à lire.

278
Eli

Que diriez-vous d'un Bash Here Document :

ssh otherhost << EOF
  ls some_folder; 
  ./someaction.sh 'some params'
  pwd
  ./some_other_action 'other params'
EOF

Pour éviter les problèmes mentionnés par @Globalz dans les commentaires, vous pourrez peut-être (en fonction de ce que vous faites sur le site distant) vous permettre de remplacer la première ligne par

ssh otherhost /bin/bash << EOF

Notez que vous pouvez effectuer une substitution de variable dans le document Here, mais que vous devrez peut-être gérer des problèmes de citation. Par exemple, si vous citez la "chaîne limite" (c'est-à-dire EOF dans ce qui précède), vous ne pouvez pas effectuer de substitution de variable. Mais sans citer la chaîne limite, les variables sont substituées. Par exemple, si vous avez défini $NAME ci-dessus dans votre script Shell, vous pouvez effectuer les opérations suivantes:

ssh otherhost /bin/bash << EOF
touch "/tmp/${NAME}"
EOF

et cela créerait un fichier sur la destination otherhost avec le nom de ce que vous auriez assigné à $NAME. D'autres règles concernant les citations de script Shell s'appliquent également, mais sont trop compliquées pour être décrites ici.

387
Paul Tomblin

Modifiez votre script localement, puis transmettez-le à ssh, par exemple.

cat commands-to-execute-remotely.sh | ssh blah_server

commands-to-execute-remotely.sh ressemble à votre liste ci-dessus:

ls some_folder
./someaction.sh
pwd;
102
bosmacs

Pour correspondre à votre exemple de code, vous pouvez insérer vos commandes entre guillemets simples ou doubles. Par exemple

ssh blah_server "
  ls
  pwd
"
32
Andrei B

Je vois deux manières:

Commencez par créer un socket de contrôle comme ceci:

 ssh -oControlMaster=yes -oControlPath=~/.ssh/ssh-%r-%h-%p <yourip>

et lancez vos commandes

 ssh -oControlMaster=no -oControlPath=~/.ssh/ssh-%r-%h-%p <yourip> -t <yourcommand>

De cette façon, vous pouvez écrire une commande ssh sans vous reconnecter au serveur.

La seconde consisterait à générer dynamiquement le script, à scpet le lancer.

31
terminus

Cela peut aussi être fait comme suit . Mettez vos commandes dans un script, nommons-le Commandes-inc.sh

#!/bin/bash
ls some_folder
./someaction.sh
pwd

Sauvegarder le fichier

Maintenant, lancez-le sur le serveur distant.

ssh user@remote 'bash -s' < /path/to/commands-inc.sh

Jamais échoué pour moi.

16
R J

SSH et exécuter plusieurs commandes dans Bash.

Des commandes séparées avec des points-virgules dans une chaîne, passées à echo, le tout dirigé dans la commande ssh. Par exemple:

echo "df -k;uname -a" | ssh 192.168.79.134

Pseudo-terminal will not be allocated because stdin is not a terminal.
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sda2       18274628 2546476  14799848  15% /
tmpfs             183620      72    183548   1% /dev/shm
/dev/sda1         297485   39074    243051  14% /boot
Linux newserv 2.6.32-431.el6.x86_64 #1 SMP Sun Nov 10 22:19:54 EST 2013 x86_64 x86_64 x86_64 GNU/Linux
8
arnab

Mettez toutes les commandes sur un script et il peut être exécuté comme

ssh <remote-user>@<remote-Host> "bash -s" <./remote-commands.sh
7
Jai Prakash

Pour ceux qui tombent comme moi ici, j'ai réussi à échapper au point-virgule et à la nouvelle ligne:

Première étape: le point-virgule. De cette façon, nous ne cassons pas la commande ssh:

ssh <Host> echo test\;ls
                    ^ backslash!

Répertorie le répertoire hosts/home distant (connecté en tant que root), tandis que

ssh <Host> echo test;ls
                    ^ NO backslash

répertorié le répertoire de travail en cours.

Prochaine étape: rompre la ligne:

                      v another backslash!
ssh <Host> echo test\;\
ls

Cette fois à nouveau répertorié le répertoire de travail distant - mise en forme améliorée:

ssh <Host>\
  echo test\;\
  ls

Si vraiment plus sympa qu'ici le document ou les citations autour des lignes brisées - bien, pas moi de décider ...

(Utilisation de bash, Ubuntu 14.04 LTS.)

5
Aconcagua

Cela fonctionne bien pour la création de scripts, car vous n'avez pas à inclure d'autres fichiers:

#!/bin/bash
ssh <my_user>@<my_Host> "bash -s" << EOF
    # here you just type all your commmands, as you can see, i.e.
    touch /tmp/test1;
    touch /tmp/test2;
    touch /tmp/test3;
EOF
4
sjas

Le moyen le plus simple de configurer votre système pour utiliser des sessions SSH uniques par défaut avec le multiplexage.

Cela peut être fait en créant un dossier pour les sockets:

mkdir ~/.ssh/controlmasters

Et ensuite, ajoutez ce qui suit à votre configuration .ssh:

Host *
    ControlMaster auto
    ControlPath ~/.ssh/controlmasters/%r@%h:%p.socket
    ControlMaster auto
    ControlPersist 10m

Maintenant, vous n'avez pas besoin de modifier votre code. Cela permet de faire plusieurs appels à ssh et scp sans créer plusieurs sessions, ce qui est utile lorsqu'il doit y avoir plus d'interaction entre vos machines locales et distantes.

Grâce à la réponse de @finus, http://www.cyberciti.biz/faq/linux-unix-osx-bsd-ssh-multiplexing-to-speed-up-ssh-connections/ et https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Multiplexing .

2
Jonathan

Les réponses affichées utilisant des chaînes multilignes et plusieurs scripts bash ne fonctionnaient pas pour moi.

  • Les longues chaînes multilignes sont difficiles à maintenir. 
  • Des scripts bash distincts ne gèrent pas les variables locales. 

Voici un moyen fonctionnel de ssh et d'exécuter plusieurs commandes tout en conservant le contexte local.

LOCAL_VARIABLE=test

run_remote() {
    echo "$LOCAL_VARIABLE"
    ls some_folder; 
    ./someaction.sh 'some params'
    ./some_other_action 'other params'
}

ssh otherhost "$(set); run_remote"
2
Michael Petrochuk

Pas sûr que ce soit le plus propre pour les longues commandes mais certainement le plus facile

ssh user@Host "cmd1; cmd2; cmd;3"
0
DimiDak