web-dev-qa-db-ja.com

Bashで複数のコマンドをSSHで実行する最もクリーンな方法は何ですか?

私はすでにsshエージェントをセットアップしています、そしてBashスクリプトで外部サーバーでコマンドを実行することができます。

ssh blah_server "ls; pwd;"

さて、私が本当にやりたいことは、外部サーバーでたくさんの長いコマンドを実行することです。これらすべてを引用符で囲むのは非常に醜いでしょう。そして、これを避けるために、何度もsshすることを避けたいのです。

それで、括弧か何かで囲まれた私がこれを一度にすることができる方法はありますか?私は以下の方針に沿って何かを探しています。

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

基本的に、私はそれがきれいである限りどんな解決策でも満足するでしょう。

編集する

明確にするために、私はこれがより大きなbashスクリプトの一部であることについて話しています。他の人がスクリプトをすぐに処理する必要があるかもしれないので、私はそれを清潔に保ちたいです。次のような1行のbashスクリプトを作成したくありません。

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

それは非常に醜くて読むのが難しいからです。

302
Eli

Bashについてはどうでしょうか こちらドキュメント

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

コメントで@Globalzによって言及されている問題を避けるために、あなたは(あなたがリモートサイトで何をしているかによって)最初の行を次のように置き換えることで済むかもしれません

ssh otherhost /bin/bash << EOF

Hereドキュメントでは変数置換を行うことができますが、引用の問題に対処する必要があるかもしれません。たとえば、「制限文字列」(つまり上記のEOF)を引用すると、変数の置換はできません。しかし制限文字列を引用せずに、変数が代入されます。たとえば、シェルスクリプトで上記の$NAMEを定義した場合は、次のようにします。

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

そしてそれは、あなたが$NAMEに割り当てたものは何でもの名前で目的地otherhostにファイルを作成するでしょう。シェルスクリプトの引用に関する他の規則も適用されますが、ここで説明するには複雑すぎます。

408
Paul Tomblin

あなたのスクリプトをローカルで編集し、それをsshにパイプしてください。

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

commands-to-execute-remotely.shは上記のリストのようになります。

ls some_folder
./someaction.sh
pwd;
112
bosmacs

サンプルコードに合わせて、コマンドを一重引用符または二重引用符で囲むことができます。例えば

ssh blah_server "
  ls
  pwd
"
36
Andrei B

2つの方法があります。

最初にこのようなコントロールソケットを作ります。

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

そしてあなたのコマンドを実行する

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

こうすれば、実際にサーバーに再接続せずにsshコマンドを書くことができます。

もう1つは、スクリプトを動的に生成し、それをscpingして実行することです。

32
terminus

これは次のようにして行うこともできます。コマンドをスクリプトに入れて、commands-inc.shという名前を付けましょう。

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

ファイルを保存する

今すぐリモートサーバーで実行します。

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

私のために失敗したことはありません。

18
R J

すべてのコマンドをスクリプトに書き込めば、次のように実行できます。

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

SSHとBashでの複数のコマンドの実行

Echoに渡された文字列内でセミコロンでコマンドを区切り、すべてsshコマンドに渡します。例えば:

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

私のようにここにつまずく人のために - 私はセミコロンと改行をエスケープすることに成功しました:

最初のステップはセミコロンです。このようにして、sshコマンドを壊しません。

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

リモートのhosts/homeディレクトリ(rootとしてログイン)を一覧表示します。

ssh <Host> echo test;ls
                    ^ NO backslash

現在の作業ディレクトリを一覧表示します。

次のステップ:行を分割する:

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

これは再びリモート作業ディレクトリをリストアップしました - 改善されたフォーマット:

ssh <Host>\
  echo test\;\
  ls

ここで説明しているよりも本当に良ければ、折れ線を囲むように文書や引用符を付けてください。

(bashを使って、Ubuntu 14.04 LTS。)

6
Aconcagua

他のファイルを含める必要がないので、これはスクリプトを作成するのに適しています。

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

デフォルトで多重化を使用して単一のsshセッションを使用するようにシステムを設定する最も簡単な方法。

これは、ソケット用のフォルダを作成することによって実行できます。

mkdir ~/.ssh/controlmasters

そして、.ssh設定に以下を追加してください。

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

今、あなたはあなたのコードのどれも修正する必要はありません。これにより、複数のセッションを作成せずにsshとscpを複数回呼び出すことができます。これは、ローカルマシンとリモートマシンの間でより多くの対話が必要な場合に便利です。

@ terminusの回答のおかげで、 http://www.cyberciti.biz/faq/linux-unix-osx-bsd-ssh-multiplexing-to-speed-up-ssh-connections/ および https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Multiplexing

2
Jonathan

複数行の文字列と複数のbashスクリプトを使用して投稿された回答が私にはうまくいきませんでした。

  • 長い複数行の文字列は維持が困難です。
  • 別々のbashスクリプトはローカル変数を管理しません。

これは、ローカルコンテキストを維持しながら複数のコマンドをSSHで実行するための機能的な方法です。

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

長いコマンドが最もクリーンかどうかはわかりませんが、最も簡単です。

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