我正在尝试在大型文本文件中搜索字符串并相应地返回退出代码。对于上下文,文本文件是ModelSim日志文件,我需要将退出代码1(坏)或0(好)传递给调用以下TCL脚本(代码段)的Windows批处理脚本:
set sim_pass {# ** Failure: NONE. End of Test: PASS}
set sim_fail {# ** Failure: ERRORS. End of Test: FAIL}
# set each_line "# ** Failure: ERRORS. End of Test: FAIL\r";
set failed_sim 0
# Set top-level paths and testbench.
global app_sim_path reg_tb_path parent_path log_directory msim_ini
set TOP_LEVEL_NAME project_io_tb
cd $app_sim_path
# Create logfile.
set sim_log_file ${parent_path}/${log_directory}/${TOP_LEVEL_NAME}_sim.log
if {[file exists $sim_log_file]} {
file delete -force $sim_log_file
}
set fs [open $sim_log_file {RDWR CREAT EXCL}]
close $fs
# Initialize ModelSim.
puts "\[INFO\] Now testing ... $TOP_LEVEL_NAME"
vsim -modelsimini $msim_ini -c -quiet -l $sim_log_file
# Compile all files required for testbench.
source compile.tcl
# Log all signals for debug.
log -r /*
# Run simulation.
run -all
quit -sim
# Read log file.
set fptr [open ${sim_log_file} r]
set log_data [read $fptr]
close $fptr
# Split file contents on new line.
set line_data [split $log_data "\n"];
# Parse each line.
foreach each_line $line_data {
# Check if simulation test failed.
if {[string match $sim_fail [string trim $each_line]]} {
set failed_sim 1
break
}
}
# Return correct exit code.
if {$failed_sim} {
puts "Simulation Failed, returning $failed_sim"
} else {
puts "Simulation Passed, returning $failed_sim"
}
exit -code $failed_sim
quit -f
执行上述脚本时至少出现两件事:
我做错了什么?
[编辑]: 谢谢大家的回复。不幸的是,我仍然无法让我的TCL脚本工作。这可能与我的日志文件包含我正在搜索的以下文本字符串这一事实有关:
# ** Failure: ERRORS. End of Test: FAIL
我无法更改文本的第一部分“#** Failure:”,因为这是ModelSim用于日志文件的语法。所以“**”可能搞砸了字符串匹配,因为我不知道如何逃避它。
我真正想做的是搜索子字符串“ERRORS。测试结束:失败”,这是我可以更改的文本。
请注意,我在 foreach 循环中使用 string 命令。
我仍然将整个日志文件的疯狂长回声发送到我的Windows命令窗口,该窗口也写入没有换行符的日志文件。我担心我没有正确打开/关闭日志文件,所以在原始代码片段中添加了更多内容。
答案 0 :(得分:1)
嗯,这些模式存在问题:
set sim_ok {# ** Failure: NONE. End of Test: PASS};
set sim_fail {# ** Failure: ERRORS. End of Test: FAIL};
是,对于一个glob模式,例如string match
所支持的,你必须匹配整个字符串,即使在分成行之后,那里也会有意外的字符。可能还有其他你不期望的东西(例如,颜色代码),但最终仍然需要匹配的字符。此外,您可能在行的末尾有空格,并且glob模式中的**
与*
相同,并且匹配任意数量的任何字符。
诊断提示
您可以通过以下方式发现此类问题:
puts [exec od -c << $the_line_contents]
但是你要小心这样做,因为极大会增加输出量。它是一个诊断工具,可以让你准确地看到你匹配的内容并轻松查找不寻常的字符,因为
od -c
将任何不可打印的ASCII转换为转义序列并将所有内容分开,但这不是你想要的东西。 (通常)留在生产中使用。
请尝试使用这些模式:
# BTW, you don't need semicolons at the end of the line
set sim_ok {# * Failure: NONE. End of Test: PASS}
set sim_fail {# * Failure: ERRORS. End of Test: FAIL}
并使用以下方式进行模式匹配:
if {[string match $sim_fail [string trim $each_line]]} {
...
处理彩色输出的最简单方法(如果这是一个问题)是将TERM
环境变量更改为不支持颜色的内容,例如vt100
或{{1}在运行生成输出的程序之前。
plain
命令不带exit
选项。只需使用直接-code
来执行此程序失败的退出。
答案 1 :(得分:0)
第一个问题是由 -nonewline 引起的。删除它。
set log_data [read $fptr]
如果将其保留,log_data将不包含换行符,因此split $log_data "\n"
将是长度为1的列表。
可能是exit命令的-code
选项。我找到的文档表明它不是受支持的选项(没有选项用于退出)。您之前可能有return
语句,其中 支持-code属性。尝试
exit $failed_sim
答案 2 :(得分:0)
为了匹配精确的子串(不是正则表达式或glob模式),[string first]
是一个很好的工具:
set sim_fail {# ** Failure: ERRORS. End of Test: FAIL};
set each_line "# ** Failure: ERRORS. End of Test: FAIL\r" ;# trailing whitespace
if {[string match $sim_fail $each_line]} {puts matched} else {puts "not matched"}
# => not matched
if {[string first $sim_fail $each_line] != -1} {puts matched} else {puts "not matched"}
# => matched
答案 3 :(得分:0)
在对我的TCL脚本进行一些调试后,我开始工作了。解决方案是:
悄悄添加&#34;&#34;在我的文件前面读到:
quietly set line_data [split [read -nonewline $fptr] "\n"]
这会关闭ModelSim的抄本回音,这是我正在使用的TCL解释器。
修复&#34; break&#34;的缩进和错位命令如下:
foreach each_line $line_data {
if {[string match $sim_fail $each_line]} {
set failed_sim 1
break
}
}
感谢您的帮助!