我正在尝试编写一个 bash 脚本来通过 ssh 重新启动多台受密码保护的计算机。我在 .txt 文件中列出了所有 IP,并希望脚本从那里读取 IP。由于我的 mac 没有 sshpass,所以我一直在弄乱 Expect 命令。有没有办法在没有 sshpass 的情况下做到这一点?
到目前为止我有这个:
#!/bin/bash
for server in 'testreboot.txt'; do
expect -c 'spawn ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5
administrator@$server "sudo shutdown -r now"; expect "Password:"; send
"password\r"; interact'
done
在 testreboot.txt 中,我只列出了测试机器的 IP 地址。可以吗还是我需要将它分配给一个变量?当我尝试运行它时,我不断收到变量错误。
答案1
您用单引号引用了该字符串;这会阻止 shell 进行插值$server
。 TCL(expect
编写代码的方式)也使用该形式来插入变量,但您在 TCL 代码中$server
没有使用该形式 。set server ...
因此会出现错误,因为 shell 没有插入它,TCL 也没有设置它。一种方法是双引号 TCL 表达式,这将允许 shell 在 shell$server
变量中进行插值:
$ server=example; expect -c 'puts $server'
can't read "server": no such variable
while executing
"puts $server"
$ server=example; expect -c "puts $server"
example
$
然而,这意味着"
TCL 代码中的任何内容都需要进行转义,以防止它们干扰 shell 插值,这可能会很快变得难看并且很难调试,特别是当命令变得更长、更复杂时。
$ server=example; expect -c "puts \"a server named '$server'\""
a server named 'example'
$
另一种选择是将参数读入 TCL 变量,但是,唉,-c
标志代码expect
无权访问参数列表
因为char *argv[]
代码-c
在参数列表可供 TCL 使用之前运行。因此,要用作$server
TCL 变量,需要用 TCL 重写脚本:
#!/usr/bin/env expect
set fh [open testreboot.txt r]
while {[gets $fh server] >= 0} {
spawn -noecho ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 \
administrator@$server
expect -ex "Password:"
send "Hunter2\r"
expect -ex {$ }
send "sudo shutdown -r now\r"
expect -ex "Password:"
send "Hunter2\r"
interact
}
这可能需要改进错误处理、超时、更好地匹配 shell 提示符等。