任何人都可以指导我如何编写tcl脚本来比较2个文本并返回不同行的行号吗? 我知道如何在bash中执行它,但是在tcl中包含bash似乎不是很整洁,这里是bash命令:
diff --old-line-format '%L' --new-line-format '' --unchanged-line-format '' <(nl File1) <(nl File2) | awk '{print $1 }' > difflines
要将其包含在tcl中,我执行了以下操作:
exec cat nl File1 > File11
exec cat nl File2 > File22
exec diff --old-line-format {%L} --new-line-format {} --unchanged-line-format {} <
File11 < File22 | awk {{print $1 }} > difflines
有更清洁的方式吗?
另外,如果有不同之处,我得到“儿童退出异常”,我该如何避免这种情况?
由于
答案 0 :(得分:2)
struct::list
中的Tcllib包具有计算最长公共子序列的工具,这是diff
工具的关键部分。要使用,您可以将数据加载到Tcl中并将其拆分为行列表:
proc getLines {filename} {
set f [open $filename]
set result [split [read $f] "\n"]
close $f
return $result
}
然后,您可以获得有关公共元素(==公共线)的信息:
set sharedLineInfo [struct::list longestCommonSubsequence $file1_lines $file2_lines]
返回一对列表,其中每个列表是公共行的索引(从零开始计算);第一个列表将用于第一个文件,第二个列表用于第二个文件。未列出的任何行号都将是已更改的行号。
还有一个功能可以反转所提供的信息,以获得有关如何将一个序列更改为另一个序列的说明:
set changes [struct::list lcsInvert $sharedLineInfo \
[llength $file1_lines] [llength $file2_lines]]
这将返回三元组列表,其中第一个是执行的操作(added
,changed
或deleted
),第二个和第三个是每个三元组的索引范围相关列表(即从零开始的行号)。
我不是非常确定如何获取这些信息并生成您想要的内容,但我想我们可以将它们组合在一起:
package require struct::list
proc getLines {filename} {
set f [open $filename]
set result [split [read $f] "\n"]
close $f
return $result
}
proc variedLines {filename1 filename2} {
set l1 [getLines $filename1]
set l2 [getLines $filename2]
lassign [struct::list longestCommonSubsequence $l1 $l2] common1
set result {}
for {set i 0} {$i < [llength $l1]} {incr i} {
if {$i ni $common1} {
lappend result [expr {$i + 1}]
}
}
return $result
}
如果您希望将结果写入文件,puts $f [join $someList "\n"]
可能会有功能,但我会将其作为练习...
答案 1 :(得分:2)
关于“儿童过程异常退出”,来自exec
man page(强调我的):
如果管道中的任何命令异常退出或被杀死或暂停,则 exec将返回错误,错误消息将包含管道的输出,然后是描述异常终止的错误消息; -errorcode返回选项将包含有关遇到的上次异常终止的其他信息。如果任何命令写入其标准错误文件并且未重定向标准错误并且未指定-ignorestderr,则 exec将返回错误;错误消息将包括管道的标准输出,后跟有关异常终止的消息(如果有),然后是标准错误输出。
“命令异常退出”表示命令以非零状态退出。一些常见命令(如grep和diff)返回非零退出状态以指示正常情况,因此您必须将该exec调用包装在catch
set rc [catch {exec bash -c {
diff --old-line-format '%L' --new-line-format '' --unchanged-line-format '' <(nl File1) <(nl File2) | awk '{print $1}' > difflines
}} output]
if {$rc == 0} {
puts "no differences found"
} elseif {$rc == 1} {
puts "differences found:"
puts $output
} else {
puts "diff returned an error: $output"
}