破碎的期望/ TCL脚本

时间:2014-06-22 14:22:13

标签: bash tcl expect

我有一个Bash脚本,它在一个单独的函数中包含expect / TCL EOF脚本。 expect脚本以0-4可能的退出代码退出,具体取决于expect / TCL脚本从远程设备确定的内容,并且在if ... elif ... else语句中,我根据此退出代码将特定字符串写入变量(在此内部)期待/ TCL功能)。然后将控制权传递回Bash脚本,其中case块在包含在所述变量中的字符串上运行。

我遇到的麻烦是我的包含expect / TCL脚本的Bash函数没有捕获退出代码3(实际上它确实如此,因为我可以看到日志文件条目正确写入日志文件,但如果我回显当情况应该为3)时,它实际捕获零的退出代码的值,因此我的case语句没有准确切换。

你能找到错误吗?

(为了保持帖子的简洁和具体,我将脚本直接切换到这些部分,以便假设周围的代码运行正常)。

function myTclFunc()
{
    /usr/bin/expect<<EOF
    proc log_msg {msg {to_stdout no}} {
        set log_line "[timestamp -format {[%d/%m/%Y @ %T]}] \$msg"
        set fh [open ~/mylogfile.log a]
        puts \$fh \$log_line
        close \$fh
        if {\$to_stdout} {puts \$log_line}
    }

    ;#exp_internal 1
    set timeout 5
    set send_human {.1 .3 1 .05 2}

    spawn ssh -o "StrictHostKeyChecking no" "[USER]@$1"

    expect {
        "password: " { send -h "[MY_PASSWD]\r" }
        timeout { log_msg "A RELEVANT STRING TO LOG $1 / $2"; exit 1 }
    }

    set timeout 3
    sleep 1 ;
    send -h "[COMMAND A]\r" ;
    expect {
        timeout { exit 1 }
        -re {\m\d{1,}(\.\d{1,}){3}\M}
    }
    if { ! [regexp {192\.[0-9]{1,3}\.{2}[0-9]{1,3}} $expect_out(0,string)]} {
        send -h "[COMMAND B]\r" ;
    }
    expect {
        "[STRING 1]" { 
            send -h "[COMMAND C]\r" ;
            log_msg "Problem F on $1 / $2" ;
            exit 3
        }
        "[STRING 2]" { 
            send -h "[COMMAND D]\r" ;
            sleep 1 ;
            send -h "[COMMAND E]\r" ;
            send -h "\r" ;
            puts "\r"
            ;#exit 0
        }
    }
    expect eof
EOF
    if [[ $? -eq 0 ]]; then
        passBack="GOOD";
    elif [[ $? -eq 3 ]]; then
        passBack="BAD";
    else
        passBack="TIMEOUT";
    fi;
}

[...snipped code...]
myTclFunc $myVar $1

case "$passBack" in
GOOD)
    echo ""
    exit 0
    ;;
BAD)
    echo ""
    exit 4
    ;;
CHECK)
    echo ""
    exit 3
    ;;
esac;
[...snipped code...]

1 个答案:

答案 0 :(得分:0)

Shell和Tcl的混合有时候会有点棘手。特别是,您希望将\传递到几个地方的正则表达式引擎中,在带有不带引号的分隔符字的here-document中。幸运的是,你把RE放在大括号里面,所以只是混淆而不是超级混乱!

bash文档的相关部分说:

  

此处文件

     

这种类型的重定向指示shell从当前源读取输入,直到看到只包含 word (没有尾随空白)的行。然后,读取到该点的所有行都将用作命令的标准输入。

     

here-documents的格式为:

   <<[-]word
       here-document
   delimiter
     

不对 word 执行参数扩展,命令替换,算术扩展或路径名扩展。如果引用 word 中的任何字符,则分隔符是对单词的引号删除的结果,并且不会展开here-document中的行。如果 word 未加引号,则here-document的所有行都要进行参数扩展,命令替换和算术扩展。在后一种情况下,将忽略字符序列 \&lt; newline&gt; ,并且必须使用 \ 来引用字符 \ $ `

     

如果重定向运算符为&lt;&lt; - ,则从输入行和包含分隔符的行中删除所有前导制表符。这允许shell脚本中的文档以自然的方式缩进。

因为您使用的是不带引号的版本,所以您希望将希望Tcl解释器看到的反斜杠加倍。在你的情况下,这只是正则表达式中的那些。因此,你想要这个(我认为上下都没有变化):

    expect {
        timeout { exit 1 }
        -re {\\m\\d{1,}(\\.\\d{1,}){3}\\M}
    }
    if { ! [regexp {192\\.[0-9]{1,3}\\.{2}[0-9]{1,3}} $expect_out(0,string)]} {
        send -h "[COMMAND B]\\r" ;
    }

哦,您还需要\\r(如上所述)整个脚本而不是\r


我认为将脚本分成两个文件会更容易,一个只是Bash代码,另一个只是Tcl代码,至少在你开发它时。然后你就可以让事情发挥作用,而不必费力地引用多层报价。 (你现在替换的东西可以作为参数传递给脚本。)

将所有内容重新打包在一起时,bash的printf %q可能会有所帮助。它会生成难以阅读的内容,但它毕竟是打包操作......


关于错误代码?问题比较简单;测试本身 - [[ $? -eq 0 ]] - 设置错误代码。您必须将其保存到适当的变量,然后对其进行测试。

在这里,检查这些煮沸的案例:

bash-3.2$ ( exit 2 ); if [[ $? -eq 0 ]]; then echo ok; elif [[ $? -eq 2 ]]; then echo good; else echo bad; fi
bad
bash-3.2$ ( exit 2 ); echo $?; if [[ $? -eq 0 ]]; then echo ok; elif [[ $? -eq 2 ]]; then echo good; else echo bad; fi
2
ok
bash-3.2$ ( exit 2 ); code=$?; echo $code; if [[ $code -eq 0 ]]; then echo ok; elif [[ $code -eq 2 ]]; then echo good; else echo bad; fi
2
good

第一个是你现在正在做的事情,第二个显示它可以得到多么不明显 - 干预echo改变了结果 - 第三个显示了如何处理它(存储code这里的值,但名称并不是那么特别。)