以下脚本读取目录文件并完成testcommands文件中的命令后,foreach函数从目录文件中查找更多信息以处理和错误,而不是结束。
#!/usr/bin/expect
set timeout 5
# Open and read hosts from file
set fp [open "inventory_2ps"]
set hosts [split [read $fp]"n"]
close $fp
# Get commands to run in server
set fh [open "testcommands"]
set commands [split [read $fh] "n"]
close $fh
# Set login variable
set user "xxxxxxx";
set PW "xxxxxxx";
# Spawn server login
foreach host $hosts {
spawn ssh $user@$host
expect "$ "
send "su - xxxxxxn"
expect "Password: "
send "$PWn"
expect "$ "
send "xxxxxx -nobashr"
expect "> "
foreach cmd $commands {
send "$cmdn"
expect "> "
}
expect eof
在最后一次主机登录/退出后收到错误:
>$ spawn ssh xxxxxx@"
ssh: Could not resolve hostname ": Name or service not known
send: spawn id exp10 not open
while executing
"send "su - xxxxxxn""
("foreach" body line 6)
invoked from within
"foreach host $hosts {
spawn ssh $user@$host
expect "$ "
您需要确保您的代码忽略输入数据中的空白值,因为它们对您的情况没有帮助。您可以在每个foreach
循环的开始处添加一些简单的过滤:
foreach host $hosts {
if {[string trim $host] eq ""} then continue
spawn ssh $user@$host
# ...
我经常喜欢使用稍微复杂一点的过滤(如下所示),这样我就可以在我的配置文件中添加注释。这在实践中是非常好的!
foreach host $hosts {
set host [string trim $host]
if {$host eq ""} then continue
if {[string match "#*" $host]} then continue
spawn ssh $user@$host
# ...
除此之外,还要确保在split
的文本和要分割的字符集之间包含一个空格。这可能是您在这里提交的一个工件,并没有出现在您的实际代码中,但它确实很重要,因为Tcl对差异很敏感。
根据TCL wiki, read命令将读取所有内容,直到遇到EOF。这包括最后一个换行符。为了丢弃最后一个换行符,您需要添加-nonewline
详情请参阅http://wiki.tcl.tk/1182
假设我们有一个包含2个主机名行的inventory_2ps文件。"host1"one_answers"host2"
$ cat inventory_2ps
host1
host2
如果我们手动运行open tcl命令,我们会得到下面的
$ tclsh
% set fp [open "inventory_2ps"]
file3
% puts [read $fp]
host1
host2
% set fp [open "inventory_2ps"]
file4
% puts [read -nonewline $fp]
host1
host2
%
修复:尝试更改以下行
set hosts [split [read $fp]"n"]
和
set commands [split [read $fh] "n"]
set hosts [split [read -nonewline $fp]]
和
set commands [split [read -nonewline $fh]]
。