在跨多个服务器的 for 循环中使用 sed 命令

在跨多个服务器的 for 循环中使用 sed 命令

我正在尝试跨多个主机操作同一个文本文件。我目前拥有的命令:

for host in $(cat /etc/hosts | grep text | cut -d' ' -f 1 | sort -u); do
    ssh $host \
    sudo sed -i "s/enabled = 1/enabled = 0/" /etc/yum.repos.d/testing.repo
done

sed 命令本身可以在主机本地运行,没有任何问题,但是当我在这里运行它时,我得到:

sed: -e expression #1, char 9: unterminated `s' command

我究竟做错了什么?

答案1

尝试这个,

for host in $(grep test /etc/hosts | cut -d' ' -f 1 | sort -u); do
    ssh $host 'sudo sed -i "s/enabled = 1/enabled = 0/" /etc/yum.repos.d/testing.repo'
done

我们应该用引号将远程命令括起来。

答案2

尝试像这样改变

for host in $(cat /etc/hosts | grep text | cut -d' ' -f 1 | sort -u); do
   ssh $host \
   "sudo sed -i \"s/enabled = 1/enabled = 0/\" /etc/yum.repos.d/testing.repo"
done

答案3

问题在于要在远程主机上执行的命令依赖于正确处理的引用。引号需要作为远程端命令的一部分进行评估,而不是在本地主机上。这意味着该命令需要额外的引号。

由于您当前的尝试没有正确引用该命令,因此它在远程主机上的空格上被分割。然后该sed命令就相当于本地运行

sed -i s/enabled = 1/enabled = 0/ /etc/yum.repos.d/testing.repo

正如错误消息所述,其中包含s未正确终止的命令。

此外,循环执行命令替换是不优雅且危险的。替换扩展的值将被拆分为空格上的单词,然后这些单词将进行文件名生成(通配)。它还要求在循环开始其第一次迭代之前完全展开命令替换。

相反,使用read循环:

awk '/text/ && !seen[$1]++ { print $1 }' |
while IFS= read -r remote; do
    ssh -n "$remote" \
        'sudo sed -i "s/enabled = 1/enabled = 0/" /etc/yum.repos.d/testing.repo'
done

注意ssh -n这里。它停止ssh读取其标准输入流,否则它会读取awk命令输出的主机。另外,任何变量扩展都应该用双引号引起来(除非您知道在什么情况下不需要这样做)。

解决此问题的另一种方法显然是推送一个文件,而不是编辑各个远程主机上的现有文件。新的将文件复制到每台计算机(可能使用scprsync)。然而,这要求该文件在每个主机上看起来应该相同。

相关内容