我正在尝试跨多个主机操作同一个文本文件。我目前拥有的命令:
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
命令输出的主机。另外,任何变量扩展都应该用双引号引起来(除非您知道在什么情况下不需要这样做)。
解决此问题的另一种方法显然是推送一个文件,而不是编辑各个远程主机上的现有文件。新的将文件复制到每台计算机(可能使用scp
或rsync
)。然而,这要求该文件在每个主机上看起来应该相同。