在 Tcl 中执行管道 shell 命令

Execute piped shell commands in Tcl

我想在 Tcl 中执行这些管道 shell 命令:

grep -v "#" inputfile | grep -v ">" | sort -r -nk7 | head

我试试:

exec grep -v "#" inputfile | grep -v ">" | sort -r -nk7 | head

并得到一个错误:

Error: grep: invalid option -- 'k'

当我尝试仅通过管道传输其中的 2 个命令时:

exec grep -v "#" inputfile | grep -v ">" 

我得到:

Error: can't specify ">" as last word in command

更新:我还尝试了 {} 和 {bash -c '...'}:

exec {bash -c 'grep -v "#" inputfile | grep -v ">"'} 

Error: couldn't execute "bash -c 'grep -v "#" inputfile | grep -v ">"'": no such file or directory

我的问题:如何在 tcl 脚本中执行初始管道命令?

谢谢

> 在这里引起了问题。

您需要将它从 tcl 中转义 shell 以使其在这里工作。

exec grep -v "#" inputfile | grep -v {\>} | sort -r -nk7 | head

或(这样更好,因为你少了一个grep

exec grep -Ev {#|>} inputfile | sort -r -nk7 | head    

如果您查看您来自 运行 的目录(假设 tclsh 或类似),您可能会看到您创建了一个奇怪的文件(即 |)之前。

在纯 Tcl 中:

package require fileutil

set lines {}
::fileutil::foreachLine line inputfile {
    if {![regexp #|> $line]} {
        lappend lines $line
    }
}
set lines [lsort -decreasing -integer -index 6 $lines]
set lines [lrange $lines 0 9]
puts [join $lines \n]\n

(-double 可能比 -integer 更合适)

编辑: 我在编写(基于 0 的)[=15] 时错误翻译了命令 sort 的(基于 1 的)-k 索引=] lsort 的选项。现在已更正。

文档:fileutil package, if, join, lappend, lrange, lsort, package, puts, regexp, set

问题是 exec 在看到 > 本身(或在单词的开头)时会做“特殊事情”,因为这表明重定向。不幸的是,没有实际的方法可以直接避免这种情况;这是 Tcl 语法系统无能为力的领域。你最终不得不做这样的事情:

exec grep -v "#" inputfile | sh -c {exec grep -v ">"} | sort -r -nk7 | head

您还可以将整个管道移动到 Unix shell 端:

exec sh -c {grep -v "#" inputfile | grep -v ">" | sort -r -nk7 | head}

虽然坦率地说,这是您可以在纯 Tcl 中完成的事情,然后它也可以移植到 Windows…