编写一个Shell脚本来SSH到远程机器并执行命令。

139

我有两个问题:

  1. 有多个远程的Linux机器,我需要编写一个shell脚本,在每台机器上执行相同的一组命令(包括sudo操作)。如何使用shell脚本完成此操作?
  2. 在ssh到远程机器时,如何处理它提示RSA指纹身份验证的情况。

这些远程机器是在运行时创建的虚拟机,并且我只有它们的IP地址。所以,我无法事先在这些机器中放置脚本文件并从我的机器上执行它们。


我想部署一个类似代理的程序到远程Linux机器上,它通过网络套接字(或SSL)连接/定期轮询服务器来保持与服务器的连接。 - Raptor
我需要执行一组命令,只需执行一次,因此无需维护连接。 - Balanivash
“no scripts” 意味着 “根本没有文件”,我猜是这样吧?你如何处理身份验证?你可以禁用主机指纹检查(请参见我的答案),但如果您没有设置公钥/私钥,仍会收到交互式密码提示。 - Andreas Fester
1
Andreas:是的。根本没有文件。可以使用 expect 来处理密码提示,如 expect "*?assword:*" - Balanivash
10个回答

181

有多台远程Linux机器,我需要编写一个Shell脚本,在每台机器上执行相同的一组命令(包括某些sudo操作)。如何使用Shell脚本完成这个任务?

您可以使用ssh来完成,例如:

#!/bin/bash
USERNAME=someUser
HOSTS="host1 host2 host3"
SCRIPT="pwd; ls"
for HOSTNAME in ${HOSTS} ; do
    ssh -l ${USERNAME} ${HOSTNAME} "${SCRIPT}"
done
当通过ssh连接到远程计算机时,如何处理RSA指纹认证提示。
你可以在ssh命令中添加 StrictHostKeyChecking=no 选项:
ssh -o StrictHostKeyChecking=no -l username hostname "pwd; ls"

这将会禁用主机密钥检查并自动将主机密钥添加到已知主机列表中。如果您不想将主机添加到已知主机文件中,请添加选项-o UserKnownHostsFile=/dev/null

请注意,这禁用了某些安全检查,例如防止中间人攻击的保护。因此,在需要安全保障的环境下不应使用该选项。


1
什么是脚本语言?当然,您也可以从任何shell脚本中调用ssh - Andreas Fester
如果您想要在SSH到多个服务器的同时执行CTRL+C怎么办?例如,在某些服务器上会要求输入密码,而在其他一些服务器上则不需要,因此脚本会卡在那里。是否有类似于“-o”的方式来执行CTRL+C或CTRL+D呢? - Chanafot
2
密码在哪里? - TomJava
我可以通过这个帮助链接在远程机器上执行一个sh文件中的脚本:cat execute-remotely.sh | ssh server - Timo

11

使用 apt-get install sshpass 安装sshpass,然后编辑脚本,并按照顺序放置您的Linux机器IP、用户名和密码。完成后运行该脚本。就这样!该脚本将在所有系统中安装VLC。

#!/bin/bash
SCRIPT="cd Desktop; pwd;  echo -e 'PASSWORD' | sudo -S apt-get install vlc"
HOSTS=("192.168.1.121" "192.168.1.122" "192.168.1.123")
USERNAMES=("username1" "username2" "username3")
PASSWORDS=("password1" "password2" "password3")
for i in ${!HOSTS[*]} ; do
     echo ${HOSTS[i]}
     SCR=${SCRIPT/PASSWORD/${PASSWORDS[i]}}
     sshpass -p ${PASSWORDS[i]} ssh -l ${USERNAMES[i]} ${HOSTS[i]} "${SCR}"
done

3
使用$SSHPASS将密码导出以避免在脚本中显示。参考:https://www.tecmint.com/sshpass-non-interactive-ssh-login-shell-script-ssh-password/ - Hexy

8

这对我有效。

语法:ssh -i pemfile.pem user_name@ip_address 'command_1 ; command 2; command 3'

#! /bin/bash

echo "########### connecting to server and run commands in sequence ###########"
ssh -i ~/.ssh/ec2_instance.pem ubuntu@ip_address 'touch a.txt; touch b.txt; sudo systemctl status tomcat.service'

1
我想在远程机器上执行一个命令,这个带有远程命令的示例脚本在ssh命令后面的同一行上帮了忙。谢谢。 - ryadavalli
如果需要使用密码登录,这个能用吗? - Prasannjeet Singh

5

有很多方法可以处理这个问题。

我最喜欢的方法是在远程系统和你自己的公钥上安装http://pamsshagentauth.sourceforge.net/。(想办法在虚拟机上安装这些文件,既然你已经安装了整个Unix系统,那么再安装几个文件又算什么呢?)

使用转发的ssh代理,您现在可以登录到每个系统而无需密码。

更好的是,该pam模块将使用您的ssh密钥对进行sudo身份验证,因此您可以根据需要以root(或任何其他用户的)权限运行。

您不需要担心主机密钥交互。如果输入不是终端,则ssh只会限制您转发代理和使用密码进行身份验证的能力。

您还应该研究像Capistrano之类的软件包。一定要查看该网站;它介绍了远程脚本的概述。

单个脚本行可能如下所示:

ssh remote-system-name command arguments ... # so, for exmaple,
ssh target.mycorp.net sudo puppet apply

3

接受的答案是逐个连接到机器。如果您想在多个机器上运行一些长时间运行的命令,如scp ,并以并行方式运行这些命令,则将ssh命令作为后台进程运行。

#!/bin/bash
username="user"
servers=("srv-001" "srv-002" "srv-002" "srv-003");
script="pwd;"
for s in "${servers[@]}"; do
    echo "sshing ${username}@${s} to run ${script}"
    (ssh ${username}@${s} ${script})& # Run in background
done
wait # If removed, you can run some other script here

2
有多种方法可以在多个远程Linux机器上执行命令或脚本。 其中一种简单且最容易的方式是通过pssh(并行ssh程序)

pssh:是一个用于在多台主机上并行执行ssh的程序。它提供了诸如向所有进程发送输入、将密码传递给ssh、将输出保存到文件以及超时等功能。

示例和用法:

连接到host1和host2,并从每个主机打印“hello,world”:

 pssh -i -H "host1 host2" echo "hello, world"

在多个服务器上通过脚本运行命令:


(保留HTML标签)
pssh -h hosts.txt -P -I<./commands.sh

使用并运行一个命令而不检查或保存主机密钥:

pssh -h hostname_ip.txt -x '-q -o StrictHostKeyChecking=no -o PreferredAuthentications=publickey -o PubkeyAuthentication=yes' -i  'uptime; hostname -f'

如果hosts.txt文件中有大量条目,比如100个,那么并行选项也可以设置为100,以确保命令同时运行。
pssh -i -h hosts.txt -p 100 -t 0 sleep 10000

选项:
-I: 读取输入并发送到每个ssh进程。
-P: 告诉pssh在到达时显示输出。
-h: 读取主机文件。
-H : [user@]host[:port] 用于单个主机。
-i: 每个主机完成时显示标准输出和标准错误
-x args: 传递额外的SSH命令行参数
-o option: 可以用于以配置文件中使用的格式提供选项。(/etc/ssh/ssh_config) (~/.ssh/config)
-p parallelism: 使用给定数字作为最大并发连接数
-q Quiet mode: 导致大多数警告和诊断消息被抑制。
-t: 在给定的秒数后使连接超时。0表示pssh不会超时任何连接

当ssh连接到远程机器时,如何处理RSA指纹身份验证提示。

禁用StrictHostKeyChecking以处理RSA身份验证提示。
-o StrictHostKeyChecking=no

来源:man pssh


1
对于这种任务,我经常使用Ansible,它可以在多个容器或虚拟机中一致地复制bash脚本。Ansible(更准确地说是Red Hat)现在有一个额外的Web界面AWX,它是他们商业版Tower的开源版本。
Ansible: https://www.ansible.com/
AWX:https://github.com/ansible/awx
Ansible Tower: 商业产品,您可能首先会探索免费的开源AWX,而不是Tower的15天免费试用。

1

如果您能编写Perl代码,那么您应该考虑使用Net::OpenSSH::Parallel

您可以以声明性的方式描述必须在每个主机上运行的操作,而模块将处理所有可怕的细节。还支持通过sudo运行命令。


1
这对我很有帮助。我创建了一个函数。将其放入您的shell脚本中:
sshcmd(){
    ssh $1@$2 $3
}

sshcmd USER HOST COMMAND

如果您有多台机器想要执行同一命令,您可以使用分号重复该行。例如,如果您有两台机器,则应这样做:
sshcmd USER HOST COMMAND ; sshcmd USER HOST COMMAND

用电脑的用户替换USER。用电脑的名称替换HOST。用您想在计算机上执行的命令替换COMMAND。
希望这可以帮助!

-1
你可以按照以下步骤进行:
  • 使用Expect脚本连接到远程机器。如果您的机器不支持expect,您可以下载相应的软件。编写Expect脚本非常容易(可以在谷歌上搜索相关帮助)。
  • 将需要在远程服务器上执行的所有操作放入一个shell脚本中。
  • 一旦登录成功,从expect脚本中调用远程shell脚本。

正如我在问题中提到的那样,远程机器是在运行时创建的,我无法预先在机器上放置任何脚本。 - Balanivash
在这种情况下,将所有操作放在Expect脚本中。Expect脚本也可以在远程主机上运行命令。 - rai.skumar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接