使用Expect如何在EOF之后退出foreach函数

时间:2016-09-07 19:26:43

标签: ssh foreach tcl expect

在以下脚本读取清单文件并完成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 - xxxxxx\n"
    expect "Password: "

    send "$PW\n"
    expect "$ "

    send "xxxxxx -nobash\r"
    expect "> "

    foreach cmd $commands {
            send "$cmd\n"
            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 - xxxxxx\n""
    ("foreach" body line 6)
    invoked from within
"foreach host $hosts {

    spawn ssh $user@$host
    expect "$ "

2 个答案:

答案 0 :(得分:1)

根据TCL wiki,read命令将读取所有内容,直到遇到EOF。这包括最后一个换行符。要丢弃上一个换行符,您需要添加 -nonewline

有关详细信息,请参阅http://wiki.tcl.tk/1182

假设我们有inventory_2ps文件,其中包含2个主机名行。 “host1”和“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]]

分别

答案 1 :(得分:1)

您需要确保您的代码忽略输入数据中的空白值,因为它们在您的案例中无用。 您可以通过在每个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对差异很敏感。