需要帮助使用 expect 从不断变化的日志文件中提取特定行
Need help extracting specific lines from a changing logfile using expect
我正在尝试使用 expect 脚本通过 telnet 访问远程设备,read/save 本地远程 "EVENTLOG",然后从日志文件中提取特定行(序列号)。问题是日志文件不断变化,所以我需要一种方法来搜索特定的字符串。远程设备基于 Linux,但没有 grep、vi、less 等,因为它是 QNX Neutrino,因此必须在本地进行。
我已经成功获得 telnet,读取文件并在本地控制下保存,但是当我到达 "reading" 时文件出现问题。目前我只是想让它打印它发现的内容,但脚本只是退出而不报告任何东西,除了一些额外的大括号??
#!/usr/bin/expect -f
set timeout -1
log_user 1
spawn telnet $IP
match_max 100000
expect "login:"
send -- "$USER\r"
expect "Password:"
send -- "$PW\r"
expect "# "
send -- "\r"
#at this point logged into device
#send command to generate the "dallaslog"
set dallaslog [open dallaslog.txt w]
expect "#"
send -- "cat `ls -rt /LOG/event*`\r"
expect "(cat) exited status=0"
set logout $expect_out(buffer)
puts $dallaslog "$logout"
close $dallaslog
unset expect_out(buffer)
set dallasread [open dallaslog.txt r]
set lines [split [read $dallasread] "\r"]
close $dallasread
puts "${green}$lines{$normal}"
#a debug line to print $dallasread in green so I can verify it works up to here
foreach line $lines {
if {[regexp {.*Dallas ID: 0.*\n} $lines match]} {
if {$match == 1} {
puts $line ;# Prints whole line which has 1 at end
}
}
}
expect "# "
send -- "exit\r"
interact
我(最终)寻找的是脚本来捕获以 "Dallas ID:" 开头的任何行,然后将该信息保存到变量中,这样我就可以使用 "scan" 命令来解析行并提取信息。
我得到的是:
(the results from $lines being "puts" in green)
"...
<ENTRY TIME="01/01/1970 00:48:07" PROC="syncd" FILE="mips.cc" LINE="208" NUM="10000">
UTC step from 01/01/1970 00:48:08 to 01/01/1970 00:48:07
</ENTRY>
Process 3174431 (cat) exited status=0
}{}
# exit
Process 3162142 (sh) exited status=0.
Connection closed by foreign host."
提前感谢您提供的所有帮助。我是 TCL/expect 的新手(自去年 7 月以来一直在玩弄它),但我发现它是一个非常强大的工具,只是我很难调试!
编辑:根据@meuh 的回复添加了更多信息。
示例:最多可以有4个Dallas ID,但一般我只有0和1。目标是获取到达拉斯ID的SN,BC,CN作为变量保存在单独的文本文件中。
<ENTRY TIME="01/01/1970 00:00:06" PROC="sys" FILE="PlatformUtils.cpp" LINE="1227" NUM="10044">
Dallas ID: 1 SN:00000622393A BC: J4AD945 CN: IS200BPPBH2BMD R0: 001C
</ENTRY>
我使用的 foreach 循环是一个关于堆栈溢出的老问题的例子,我试图修改以在这里使用,但没有成功。
编辑:我还应该提一下,这个事件日志每次被阅读时大约有 800 行长,这就是为什么我没有发布它的摘录。
此正则表达式行可能没有按照您的要求执行:
if {[regexp {.*Dallas ID: 0.*\n} $lines match]} {
if {$match == 1} {
puts $line
您传递的是列表 $lines
而不是单行 $line
。变量 match
将被设置为匹配的字符串,因此必须包含单词 "Dallas" 等等,因此它永远不会是 1。
您的代码注释说 Prints whole line which has has 1 at end,但我不确定您在寻找什么,因为您没有任何适合正则表达式的示例数据。
如果您选择使用分组的正则表达式模式,您可以捕获部分行,因此可能不需要进一步 scan
。例如
regexp {PROC="([a-z]*)"} $line match submatch
会在上面的示例中将变量子匹配设置为 syncd
。
您可能还遇到了一个基本问题,该问题是由 tcl 对文件输入的 \r\n
处理引起的。你从 $expect_out(buffer)
得到的行确实有 2 个字符作为行尾分隔符。然而,
当使用 read
时,我相信默认情况下,它会将相同的序列转换为规范化的 \n
。所以你的拆分不会做任何事情,你需要在 \n
而不是 \r
上拆分。您可以使用
检查行列表的大小
puts [llength $lines]
如果为 1,则说明您的拆分无效。将其替换为
set lines [split [read $dallasread] "\n"]
这应该有助于你的循环,例如你可以尝试
foreach line $lines {
if {[regexp {.*Dallas ID: (\d+) SN:([^ ]+)} $line match idnum SN]} {
puts $line
puts "$idnum, $SN"
}
}
您必须删除正则表达式末尾的 \n
,因为它在拆分后不再存在。我用 (\d+)
扩展了正则表达式示例以匹配 ID 号(\d
匹配一个数字),并使用 ([^ ]+)
匹配之后任意数量的非 space 字符文本 SN:
。
这些值是通过使用 ()
分组捕获的,并放置在变量 idnum 和 SN 中,您应该能够在第二个 puts
命令中看到输出。
我正在尝试使用 expect 脚本通过 telnet 访问远程设备,read/save 本地远程 "EVENTLOG",然后从日志文件中提取特定行(序列号)。问题是日志文件不断变化,所以我需要一种方法来搜索特定的字符串。远程设备基于 Linux,但没有 grep、vi、less 等,因为它是 QNX Neutrino,因此必须在本地进行。
我已经成功获得 telnet,读取文件并在本地控制下保存,但是当我到达 "reading" 时文件出现问题。目前我只是想让它打印它发现的内容,但脚本只是退出而不报告任何东西,除了一些额外的大括号??
#!/usr/bin/expect -f
set timeout -1
log_user 1
spawn telnet $IP
match_max 100000
expect "login:"
send -- "$USER\r"
expect "Password:"
send -- "$PW\r"
expect "# "
send -- "\r"
#at this point logged into device
#send command to generate the "dallaslog"
set dallaslog [open dallaslog.txt w]
expect "#"
send -- "cat `ls -rt /LOG/event*`\r"
expect "(cat) exited status=0"
set logout $expect_out(buffer)
puts $dallaslog "$logout"
close $dallaslog
unset expect_out(buffer)
set dallasread [open dallaslog.txt r]
set lines [split [read $dallasread] "\r"]
close $dallasread
puts "${green}$lines{$normal}"
#a debug line to print $dallasread in green so I can verify it works up to here
foreach line $lines {
if {[regexp {.*Dallas ID: 0.*\n} $lines match]} {
if {$match == 1} {
puts $line ;# Prints whole line which has 1 at end
}
}
}
expect "# "
send -- "exit\r"
interact
我(最终)寻找的是脚本来捕获以 "Dallas ID:" 开头的任何行,然后将该信息保存到变量中,这样我就可以使用 "scan" 命令来解析行并提取信息。
我得到的是:
(the results from $lines being "puts" in green)
"...
<ENTRY TIME="01/01/1970 00:48:07" PROC="syncd" FILE="mips.cc" LINE="208" NUM="10000">
UTC step from 01/01/1970 00:48:08 to 01/01/1970 00:48:07
</ENTRY>
Process 3174431 (cat) exited status=0
}{}
# exit
Process 3162142 (sh) exited status=0.
Connection closed by foreign host."
提前感谢您提供的所有帮助。我是 TCL/expect 的新手(自去年 7 月以来一直在玩弄它),但我发现它是一个非常强大的工具,只是我很难调试!
编辑:根据@meuh 的回复添加了更多信息。 示例:最多可以有4个Dallas ID,但一般我只有0和1。目标是获取到达拉斯ID的SN,BC,CN作为变量保存在单独的文本文件中。
<ENTRY TIME="01/01/1970 00:00:06" PROC="sys" FILE="PlatformUtils.cpp" LINE="1227" NUM="10044">
Dallas ID: 1 SN:00000622393A BC: J4AD945 CN: IS200BPPBH2BMD R0: 001C
</ENTRY>
我使用的 foreach 循环是一个关于堆栈溢出的老问题的例子,我试图修改以在这里使用,但没有成功。
编辑:我还应该提一下,这个事件日志每次被阅读时大约有 800 行长,这就是为什么我没有发布它的摘录。
此正则表达式行可能没有按照您的要求执行:
if {[regexp {.*Dallas ID: 0.*\n} $lines match]} {
if {$match == 1} {
puts $line
您传递的是列表 $lines
而不是单行 $line
。变量 match
将被设置为匹配的字符串,因此必须包含单词 "Dallas" 等等,因此它永远不会是 1。
您的代码注释说 Prints whole line which has has 1 at end,但我不确定您在寻找什么,因为您没有任何适合正则表达式的示例数据。
如果您选择使用分组的正则表达式模式,您可以捕获部分行,因此可能不需要进一步 scan
。例如
regexp {PROC="([a-z]*)"} $line match submatch
会在上面的示例中将变量子匹配设置为 syncd
。
您可能还遇到了一个基本问题,该问题是由 tcl 对文件输入的 \r\n
处理引起的。你从 $expect_out(buffer)
得到的行确实有 2 个字符作为行尾分隔符。然而,
当使用 read
时,我相信默认情况下,它会将相同的序列转换为规范化的 \n
。所以你的拆分不会做任何事情,你需要在 \n
而不是 \r
上拆分。您可以使用
puts [llength $lines]
如果为 1,则说明您的拆分无效。将其替换为
set lines [split [read $dallasread] "\n"]
这应该有助于你的循环,例如你可以尝试
foreach line $lines {
if {[regexp {.*Dallas ID: (\d+) SN:([^ ]+)} $line match idnum SN]} {
puts $line
puts "$idnum, $SN"
}
}
您必须删除正则表达式末尾的 \n
,因为它在拆分后不再存在。我用 (\d+)
扩展了正则表达式示例以匹配 ID 号(\d
匹配一个数字),并使用 ([^ ]+)
匹配之后任意数量的非 space 字符文本 SN:
。
这些值是通过使用 ()
分组捕获的,并放置在变量 idnum 和 SN 中,您应该能够在第二个 puts
命令中看到输出。