0

谁能指导我如何编写 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

有没有更清洁的方法?

另外,如果我得到“孩子异常退出”的差异,我该如何避免这种情况?

谢谢

4

2 回答 2

2

Tcllib中的struct::list包有计算最长公共子序列的工具,这是工具的关键部分。要使用,您将数据加载到 Tcl 中并将其拆分为行列表:diff

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]]

这将返回一个三元组列表,其中第一个是执行的操作(addedchangeddeleted,第二个和第三个是每个相关列表中的索引范围(即从零开始的行号)。

不太确定如何获取这些信息并产生您正在寻找的东西,但我想我们可以像这样把它放在一起:

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"]可能会出现功能,但我将把它留作练习......</p>

于 2013-01-19T13:12:35.727 回答
2

关于“子进程异常退出”,来自exec手册页(强调我的):

如果管道中的任何命令异常退出或被终止或挂起,则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"
}
于 2013-01-19T15:44:52.990 回答