我在bash中有一个脚本,它为我网络上的每个元素调用一个TCL脚本,该脚本根据元素的类型执行一些操作。这是代码的一部分,它检查主机名是否包含特定模式(例如* CGN01),然后向该机器提供适当的命令。
if {[string match "{*CGN01}" $hostname] || $hostname == "AthMet1BG01"} {
expect {
"*#" {send "admin show inventory\r"; send "exit\r"; exp_continue}
eof
}
}
使用上面引用的代码,当主机名是" PhiMSC1CGN01"时,我得到没有错误。然后if中的代码没有执行,这意味着表达式不正确。
我已尝试过所有内容(使用"()"或" {}"或" []"在if内部但是当我不放""在模式上我得到一个错误:
invalid bareword "string"
in expression "(string match {*DR0* *1TS0* *...";
should be "$string" or "{string}" or "string(...)" or ...
(parsing expression "(string match {*DR0* *...")
invoked from within
"if {$hostname == "AthMar1BG03" || [string match *CGN01 $hostname]...
或者这个:
expected boolean value but got "[string match -nocase "*CGN01" $hostname]==0"
while executing
"if {$hostname == "AthMar1BG03" || {[string match -nocase "*CGN01" $hostname]==0}...
当我尝试在表达式上使用== 0或== 1时。 我的TCL版本是8.3,我无法更新它,因为该机器没有互联网连接:(
请帮助我,我试图解决这个问题超过一个月......
答案 0 :(得分:1)
如果要匹配正好为AthMet1BG01
的字符串或任何以CGN01
结尾的字符串,则应使用
if {[string match *CGN01 $hostname] || $hostname == "AthMet1BG01"} {
(对于Tcl 8.5或更高版本,请使用eq
代替==
。)
有关您尝试的一些评论:
(关于if
使用的表达式语言的注释也适用于expr
和while
。它在expr
的文档中有详细说明。)
要在条件内调用命令并替换其结果,需要将其括在括号中([
]
)。括号((
)
)可用于设置条件中子表达式的优先级,但不表示命令替换。
通常,条件字符串内部需要用双引号或括号括起来({
}
)。这是因为用于表达条件的表达语言需要区分例如数字和字符串,Tcl一般不会。在条件中的命令替换内,只要字符串中没有您需要引用的字符,不就需要使用引号或大括号。
字符串{abc}
包含字符abc
。字符串"{abc}"
包含字符{abc}
,因为双引号使大括号成为正常字符(反之亦然)。 [string match "{*bar}" $str]
匹配字符串{foobar}
(大括号作为文本的一部分),但不匹配foobar
。
如果在命令替换{[incr foo]}
周围添加大括号,则它变为字符串[incr foo]
,即不调用该命令并且不进行替换。如果您使用{[incr foo]==1}
,则会收到字符串[incr foo]==1
。在表达式中写入此内容的正确方法是[incr foo]==1
,==
周围有可选的空格。
这一切都有点难以理解,但是当你拥有它时非常容易使用。 Tcl顽固地说是解释弦乐的骡子,但是如果你对她正确的话会带来沉重的负担。
ETA 备用匹配器(请参阅注释)
您可以编写自己的备用字符串匹配器:
proc altmatch {patterns string} {
foreach pattern $patterns {
if {[string match $pattern $string]} {
return 1
}
}
return 0
}
如果任何模式匹配,则得到1;如果没有任何模式匹配,则得到0。
% altmatch {*bar f?o} foobar
1
% altmatch {*bar f?o} fao
1
% altmatch {*bar f?o} foa
0
对于那些拥有现代Tcl版本的用户,您实际上可以将其添加到string
集合中,以便它像其他string
命令一样工作。把它放在正确的命名空间中:
proc ::tcl::string::altmatch {patterns string} {
... as before ...
并像这样安装:
% set map [namespace ensemble configure string -map]
% dict set map altmatch ::tcl::string::altmatch
% namespace ensemble configure string -map $map
答案 1 :(得分:1)
此命令:
if {[string match "{*CGN01}" $hostname] || $hostname == "AthMet1BG01"} {
语法有效,但我真的不认为您想要将该模式与string match
一起使用。我猜你真的想要:
if {[string match "*CGN01" $hostname] || $hostname == "AthMet1BG01"} {
该模式中的{
大括号}
实际上没有意义(string match
只能完成全局匹配的全部功能的一部分)所以对于你的错误模式,你实际上是尝试匹配{
开头的$hostname
,任意数量的字符,然后CGN01}
结尾$hostname
。 使用文字大括号。 只需移除大括号即可PhiMSC1CGN01
匹配。