yorgo
yorgo

Reputation: 507

Execute piped shell commands in Tcl

I want to execute these piped shell commands in Tcl:

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

I try:

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

and get an error:

Error: grep: invalid option -- 'k'

When I try to pipe only 2 of the commands:

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

I get:

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

Update: I also tried {} and {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

My question: how can I execute the initial piped commands in a tcl script?

Thanks

Upvotes: 2

Views: 7529

Answers (3)

Peter Lewerin
Peter Lewerin

Reputation: 13252

In pure 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 might be more appropriate than -integer)

Edit: I mistranslated the (1-based) -k index for the command sort when writing the (0-based) -index option for lsort. It is now corrected.

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

Upvotes: 2

Etan Reisner
Etan Reisner

Reputation: 80921

The > is causing problems here.

You need to escape it from tcl and the shell to make it work here.

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

or (and this is better since you have one less grep)

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

If you look in the directory you were running this from (assuming tclsh or similar) you'll probably see that you created an oddly named file (i.e. |) before.

Upvotes: 2

Donal Fellows
Donal Fellows

Reputation: 137557

The problem is that exec does “special things” when it sees a > on its own (or at the start of a word) as that indicates a redirection. Unfortunately, there's no practical way to avoid this directly; this is an area where Tcl's syntax system doesn't help. You end up having to do something like this:

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

You can also move the entire pipeline to the Unix shell side:

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

Though to be frank this is something that you can do in pure Tcl, which will then make it portable to Windows too…

Upvotes: 4

Related Questions