我正在使用tcl来执行一些模式匹配。以下是我正在对其执行匹配的字符串:
ps -ef | grep ipqosmgr
root 17255 17136 0 22:34 ttyS0 00:00:00 grep ipqosmgr
root 28986 17731 0 Jun05 ? 00:02:01 /isan/bin/ipqosmgr
通常我会想要第三行
root 28986 17731 0 Jun05 ? 00:02:01 /isan/bin/ipqosmgr
因为我想要与进程关联的进程 ID。
当我使用以下正则表达式时,它按预期工作:
% foreach line [split $output n] {
if { [ regexp -nocase {roots+([0-9]+)s+.*(/isan/bin/ipqosmgr)} $line - value ] } {
puts $line
}
}
root 28986 17731 0 Jun05 ? 00:02:01 /isan/bin/ipqosmgr
% puts $value
28986
%
但是,我希望此代码为多个进程运行,因此将其放入一个具有$process的函数中,该函数将保存进程的值。当我对变量$process使用相同的正则表达式时,它会失败。
% puts $process
ipqosmgr
%
% foreach line [split $output n] {
if { [ regexp -nocase {roots+([0-9]+)s+.*(/isan/bin/$process)} $line - value ] } {
puts $line
}
}
%
% puts $value
can't read "value": no such variable
%
我不知道为什么它以这种方式行事,如果有人能告诉我这里出了什么问题以及如何纠正它,那就太好了。
您可以使用format
准备正则表达式,如下所示:
foreach line [split $output n] {
set regex [format {roots+([0-9]+)s+.*(/isan/bin/%s)} $process]
if { [ regexp -nocase $regex $line - value ] } {
puts $line
}
}
使用表达式的方式的问题在于大括号会阻止变量替换,虽然您可以使用引号代替正则表达式,但您必须转义许多字符(例如方括号、反斜杠(并且为了避免转义这些字符,使用format
可以更简单易用。
如果您打算使用字符串迭代,则应使用双引号字符串文字,并注意转义[
和]
以防止将它们解释为命令以及转义每个以定义文字反斜杠(例如,此处
s
速记字符类(:
regexp -nocase "root\s+([0-9]+)\s+.*(/isan/bin/$process)" $line - value
在线观看 Tcl 演示。
这里
root
- 子字符串root
\s+
- 解析为s+
- 1 个或多个空格字符([0-9]+)
- 解析为([0-9]+)
- 捕获组 1 - 1 个或多个数字\s+
- 1 个或多个空格.*
- 任何 0+ 字符(/isan/bin/$process)
- 解析为(/isan/bin/ipqosmgr)
- 捕获与/isan/bin/ipqosmgr
子字符串(或任何/isan/bin/
+$process
(匹配的组 1
。
在subst
命令中使用变量替换。此外,如果指定了任何-nobackslashes
、-nocommands
或-novariables
,则不会执行相应的替换。例如,如果指定了-nocommands
,则不执行命令替换:左括号和右括号被视为普通字符,没有特殊解释。
% set output "
root 17255 17136 0 22:34 ttyS0 00:00:00 grep ipqosmgr
root 28986 17731 0 Jun05 ? 00:02:01 /isan/bin/ipqosmgr
"
并设置变量
% set process "ipqosmgr"
你完全可以做到,
% foreach line [split $output n] {
if { [ regexp -nocase [subst -nocommands -nobackslashes {roots+([0-9]+)s+.*(/isan/bin/$process)}] $line - value ] } {
puts $line
}
}
root 28986 17731 0 Jun05 ? 00:02:01 /isan/bin/ipqosmgr
匹配是否按预期进行
% puts $value
28986