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

Expect脚本批量配置远程服务器UFW规则时获取内网IP报错排查

问题原因

报错核心是Expect(基于Tcl语法)的变量解析规则冲突:

  • 你写在ssh远程命令里的$(...)shell命令替换,会被Tcl识别成本地变量引用,直接尝试读取括号内命名的变量,不会把这段逻辑传给远程服务器执行,因此触发「找不到对应变量」的错误。
  • 原脚本里grep匹配IP的正则多写了无意义的转义方括号,即使解决解析问题也无法正确提取私网IP。
修复方案

需要做4处核心调整:

  1. 给远程命令里的$加反斜杠转义为\$,告诉Tcl不要解析这部分内容,原样传给远程shell执行
  2. 修正grep提取IP的正则错误,补全反斜杠转义避免被Tcl吞掉转义符
  3. 补充sudo密码提示的匹配规则,避免执行sudo时卡住
  4. 调整超时逻辑,单台服务器连接超时不中断整个批量流程,补充eof捕获避免脚本执行后挂死

修复后的完整脚本如下:

#!/usr/bin/expect

# 采集SSH登录用户名
send_user "user: "
expect_user -re "(.*)\n"
set user $expect_out(1,string)

# 采集登录密码(关闭输入回显)
stty -echo
send_user -- "Password for $user: "
expect_user -re "(.*)\n"
send_user "\n"
stty echo
set pass $expect_out(1,string)

# 遍历指定私网网段
for {set i 1} {$i < 10} {incr i 1} {
    spawn ssh -t $user@192.168.1.$i "sudo ufw allow from X.X.X.X to \$(ip a |grep '192.168.1' | grep -Po 'inet \\K[\d.]+') port YYYY"

    set timeout 5
    expect {
        timeout {
            puts "Connection to 192.168.1.$i timed out, skip"
            close
            continue
        }

        "yes/no" {
            send "yes\r"
            exp_continue
        }

        "assword:" {
            send -- "$pass\r"
            exp_continue
        }

        "*sudo*password*" {
            send -- "$pass\r"
            exp_continue
        }

        eof {
            puts "UFW rule added on 192.168.1.$i successfully"
        }
    }
}
使用注意事项
  • 使用前把脚本里的X.X.X.X替换为实际需要放通的源IP/网段,YYYY替换为要开放的对应端口
  • 如果需要遍历更大的网段,直接修改for循环的终止条件即可,比如要覆盖1-254地址,就把{$i < 10}改成{$i <= 254}
  • 如果你的私网网段不是192.168.1.0/24,同步修改ssh连接地址段、grep过滤的网段关键字即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 05:42:13