「OpenSSH」- 在远程服务器中执行命令

  CREATED BY JENKINSBOT

问题描述

为了维护服务器,我们通常使用 SSH 连接到服务器,然后开始敲入命令,回车执行。

但是,有的时候,我们需要在多台远程主机中,执行多条命令。此时,我们总不能 SSH 登录每台机器,然后人工输入执行吧。

该笔记将记录:在远程主机中,如何使用 OpenSSH 非交互式的执行命令的方法,以及常见问题处理。

解决方案

在远程主机中,执行单条命令

执行如下命令,将在远程服务上创建 /tmp/foo 目录:

ssh -n root@remote-ip-address 'mkdir -pv /tmp/foo'

为什么需要使用 -n 选项?参考 常见问题处理 部分。

在远程主机中,执行多条命令

如果需要执行多行命令,可以使用如下形式:

ssh root@remote-ip-address << EOF
# cmd1
# cmd2
# cmd3
EOF

常见问题处理

关闭 MOTD 消息

linux – Stop ssh login from printing motd from the client? – Server Fault

MOTD,message of the day,每次登录服务器的时候,都会显示很多行消息,那就是 MOTD 消息。但是,我们从来都不看,也不知道有多少人认真看这些消息。

现在的问题是:通过 SSH 远程执行命令时,每次都会显示这些消息,导致命令的日志输出混乱。我们希望可以抑制这些消息。

有以下解决方法:
1)在远程服务器中,创建 ~/.hushlogin 文件(不需要写入任何内容)。该方法仅是禁用登录用户的消息,其他用户依旧会提示 MOTD 消息。
2)如果要禁用所有用户的 MOTD 消息,需要修改 SSH 服务配置。在我们的环境中,我们没有采用这种方式(因为没有必要)。这里仅做记录:

// 修改 /etc/ssh/sshd_config 文件,进行如下配置
...
PrintMotd no
PrintLastLog no
...

// 修改 /etc/pam.d/ssh 文件,注释如下配置行
...
# session    optional     pam_motd.so
...

命令 while read ssh 仅循环一次(-n)

如下脚本,将执行三次,并输出信息:

server_list="\
127.0.0.1
127.0.0.2
127.0.0.3"

echo "$server_list" | while read ip_address
do
    echo "# IP Address: $ip_address"
done

# IP Address: 127.0.0.1
# IP Address: 127.0.0.2
# IP Address: 127.0.0.3

但是,如下脚本,仅执行一次:

server_list="\
127.0.0.1
127.0.0.2
127.0.0.3"

echo "$server_list" | while read ip_address
do
    echo "# IP Address: $ip_address"
    ssh $ip_address hostname
done

# IP Address: 127.0.0.1
# laptop (这是我们的主机名)

因为 SSH 会从标准输入读取,导致第一行内容被 read 读取之后,剩下的内容全被 ssh 读取。当进入第二轮循环时,标准输入已经为空,因此循环结束。

该问题的解决方式有以下两种(等价的):

ssh -n $ip_address hostname
ssh $ip_address hostname </dev/null

参考文献

What is the cleanest way to ssh and run multiple commands in Bash?
Run / Execute Command Using SSH
linux – Stop ssh login from printing motd from the client? – Server Fault