我有一个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...]
答案 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
这里的值,但名称并不是那么特别。)