How to script multiple ssh and scp commands to various systems

醉酒当歌 提交于 2019-12-06 15:45:42
Gordon Davisson

You can simplify this process a lot by tunneling ssh connections over other ssh connections (see this previous answer). The way I'd do it is to create an .ssh/config file on the LOCAL system with the following entries:

Host SYSTEM3
        ProxyCommand    ssh -e none SYSTEM2 exec /usr/bin/nc %h %p 2>/dev/null
        HostName        SYSTEM3.full.domain
        User            system3user

Host SYSTEM2
        ProxyCommand    ssh -e none SYSTEM1 exec /usr/bin/nc %h %p 2>/dev/null
        HostName        SYSTEM2.full.domain
        User            system2user

Host SYSTEM1
        HostName        SYSTEM1.full.domain
        User            system1user

(That's assuming both intermediate hosts have netcat installed as /usr/bin/nc -- if not, you may have to find/install some equivalent way of gatewaying stdin&stdout into a TCP session.)

With this set up, you can use scp SYSTEM3:/data /data on LOCAL, and it'll automatically tunnel through SYSTEM1 and SYSTEM2 (and ask for the passwords for the three SYSTEMn's in order -- this can be a little confusing, especially if you mistype one).

If you're connecting to multiple systems, and especially if you have to forward connections through intermediate hosts, you will want to use public key authentication with ssh-agent forwarding enabled. That way, you only have to authenticate once.

Scripted SSH with agent forwarding may suffice if all you need to do is check the exit status from your remote commands, but if you're going to do anything complex you might be better off using expect or expect-lite to drive the SSH/SCP sessions in a more flexible way. Expect in particular is designed to be a robust replacement for interactive sessions.

If you stick with shell scripting, and your filenames change a lot, you can always create a wrapper around SSH or SCP like so:

# usage: my_ssh [remote_host] [command_line]
# returns: exit status of remote command, or 255 on SSH error
my_ssh () {
    local host="$1"
    shift
    ssh -A "$host" "$@"
}

Between ssh-agent and the wrapper function, you should have a reasonable starting point for your own efforts.

glglgl

Another way could be to use rsync, which tomatically creates any needed directories and, if you want, removes the copied source files.

In your case, you could work with the commands

home:~$ ssh system1
system1:~$ ssh system2
system2:~$ rsync -aPSHiv system3:/data /tmp/data
system2:~$ exit
system1:~$ rsync -aPSHiv --remove-source-files system2:/tmp/data /tmp/data
system1:~$ rsync -aPSHiv system2:/data /tmp/data
system1:~$ exit
home:~$ rsync -aPSHiv --remove-source-files system1:/tmp/data /tmp/data
home:~$ rsync -aPSHiv system1:/data /data

If you combine this with Gordon's approach, you can even reduce that to

home:~$ rsync -aPSHiv system1:/data/ system2:/data/ system3:/data/ /data/

Note that rsync makes a difference between ...data and ...data/ - the former means the directory and its contents, the latter just the contents. If you mix them up, you might end up with a directory data in another directory data.

Besides, you simplify things if you work with public SSH keys instead of passwords.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!