You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Expect脚本远程自动化安装RPM时Bash变量引用报错的排查与解决

问题描述

我正在用Expect脚本实现RPM包的远程自动化安装,但在将Bash变量引入Expect脚本时遇到了问题。我希望获取远程主机的hostname并赋值给变量,之后在sed命令中使用该变量,但运行脚本时出现错误:can't read "(hostname)": no such variable。以下是我的原始脚本:

#!/usr/bin/expect
set timeout 15
set operador "operador"
set password_operador "a123456"
set password_root "123456a"
set Zabbix_IP "10.1.10.10"
#set Zabbix_IP [exec hostname -I]
#set Zabbix_IP [exec hostname -I|cut -f1 -d' ']
set f [open "hosts"]
set hosts [split [read $f] "\n"]
close $f
foreach host $hosts {
    if { ! ( $host == "" ) } {
        spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no $operador@$host
        expect "password: "
        send "$password_operador\r"
        expect "$ "
        send "su -\r"
        expect ": "
        send "$password_root\r"
        send "rpm -iv /home/operador/Zabbix_Packages_Configs/zabbix-agent2-5.0.2-1.el6.x86_64.rpm \r"
        send "sleep 1 \r"
        expect "# "
        send "V_HostNameZabbix=$(hostname)_SRV \r"
        send "V_MetaData=TimBR_Linux_SRV_SPO \r"
        send "sed -i \"s/^Server=127.0.0.1/Server=$Zabbix_IP/g\" /etc/zabbix/zabbix_agent2.conf \r"
        send "sed -i \"s/^ServerActive=127.0.0.1/ServerActive=$Zabbix_IP/g\" /etc/zabbix/zabbix_agent2.conf \r"
        send "sed -i \"s/^Hostname=Zabbix server/Hostname=$V_HostNameZabbix/g\" /etc/zabbix/zabbix_agent2.conf \r"
        expect "# "
        send "exit\r"
        expect "$ "
        send "exit\r"
    }
}

问题原因

这个错误的核心是Expect的变量解析机制和Bash的变量语法冲突:

  1. Expect会把$(hostname)中的$当成自己的变量引用符号,试图解析(hostname)这个Expect变量,但它根本不存在,所以直接报错。
  2. 同样,$V_HostNameZabbix也会被Expect优先解析,但这个变量在Expect脚本里没有提前定义,后续执行也会触发未找到变量的错误。

解决方案

要解决这个问题,我们需要让Expect把Bash的变量语法原封不动地传给远程Shell执行,同时在Expect中预先声明相关变量避免解析报错:

步骤1:在Expect脚本开头声明空变量

在脚本开头添加以下两行,让Expect识别这些变量名,避免解析时触发未找到变量的错误:

# 设置空变量,避免Expect解析时报错
set V_HostNameZabbix ""
set V_MetaData ""

步骤2:转义Bash命令中的$符号

对于需要在远程Bash中执行的变量引用(比如$(hostname)和$V_HostNameZabbix),要在$前面加反斜杠\,让Expect不解析这个$,直接把完整的Bash命令传给远程Shell执行:

# 转义$(hostname)中的$,让远程Bash执行hostname命令
send "V_HostNameZabbix=\$(hostname)_SRV \r"
# 转义$V_HostNameZabbix中的$,让远程Bash使用自己的变量
send "sed -i \"s/^Hostname=Zabbix server/Hostname=\$V_HostNameZabbix/g\" /etc/zabbix/zabbix_agent2.conf \r"

修正后的完整脚本

#!/usr/bin/expect
set timeout 15
set operador "operador"
set password_operador "a123456"
set password_root "123456a"
set Zabbix_IP "10.1.10.10"
# 设置空变量,避免Expect解析时报错
set V_HostNameZabbix ""
set V_MetaData ""
#set Zabbix_IP [exec hostname -I]
#set Zabbix_IP [exec hostname -I|cut -f1 -d' ']
set f [open "hosts"]
set hosts [split [read $f] "\n"]
close $f
foreach host $hosts {
    if { ! ( $host == "" ) } {
        spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no $operador@$host
        expect "password: "
        send "$password_operador\r"
        expect "$ "
        send "su -\r"
        expect ": "
        send "$password_root\r"
        send "rpm -iv /home/operador/Zabbix_Packages_Configs/zabbix-agent2-5.0.2-1.el6.x86_64.rpm \r"
        send "sleep 1 \r"
        expect "# "
        send "V_HostNameZabbix=\$(hostname)_SRV \r"
        send "V_MetaData=TimBR_Linux_SRV_SPO \r"
        send "sed -i \"s/^Server=127.0.0.1/Server=$Zabbix_IP/g\" /etc/zabbix/zabbix_agent2.conf \r"
        send "sed -i \"s/^ServerActive=127.0.0.1/ServerActive=$Zabbix_IP/g\" /etc/zabbix/zabbix_agent2.conf \r"
        send "sed -i \"s/^Hostname=Zabbix server/Hostname=\$V_HostNameZabbix/g\" /etc/zabbix/zabbix_agent2.conf \r"
        expect "# "
        send "exit\r"
        expect "$ "
        send "exit\r"
    }
}

这样修改后,脚本就能正常运行,远程主机的hostname会被正确捕获并用于sed命令的替换操作。

内容的提问来源于stack exchange,提问作者Anderson Silva

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 13:42:43