Daniel Heinrich
Daniel Heinrich

Reputation: 790

Get the return code of the process created by open in TCL

Right now I'm calling an external bash script via open, because said script might run for seconds or it might run for minutes. The only things that are certain are:

  1. It will output text which has to be displayed to the user. Not after the script is done, but while it is still running.
  2. It will set a return code with different meanings

Reading and using the text outputted by the shell script does work. But I don't have a clue on how to read the return code.

The (simplified) TCL script looks like this:

#!/usr/bin/tclsh

proc run_script {} {
    set script "./testing.sh"

    set process [open "|${script}" "r"]
    chan configure $process -blocking 0 -translation {"lf" "lf"} -encoding "iso8859-1"

    while {[eof $process] == 0} {
        if {[gets $process zeile] != -1} {
            puts $zeile
        }

        update
    }
    close $process

    return "???"
}

set rc [run_script]
puts "RC = ${rc}"

The (simplified) shell script does look like this:

#!/bin/bash

echo Here
sleep 1
echo be
sleep 2
echo dragons
sleep 4
echo ....
sleep 8

exit 20

So how do I read the return code of the shell script via tcl?

Upvotes: 5

Views: 1292

Answers (2)

Schelte Bron
Schelte Bron

Reputation: 4813

You need to switch the file descriptor back to blocking before you close it to get the exit code. For example:

You can use try ... trap, which was implemented with tcl 8.6:

chan configure $process -blocking 1
try {
    close $process
    # No error
    return 0
} trap CHILDSTATUS {result options} {
    return [lindex [dict get $options -errorcode] 2]
}

An other option would be to use catch:

chan configure $process -blocking 1
if {[catch {close $process} result options]} {
   if {[lindex [dict get $options -errorcode] 0] eq "CHILDSTATUS"} {
       return [lindex [dict get $options -errorcode] 2]
   } else {
       # Rethrow other errors
       return -options [dict incr options -level] $result
   }
}
return 0

Upvotes: 4

Donal Fellows
Donal Fellows

Reputation: 137587

To get the status in 8.5, use this:

fconfigure $process -blocking 1
if {[catch {close $process} result options] == 1} {
    set code [dict get $options -errorcode]
    if {[lindex $code 0] eq "CHILDSTATUS"} {
        return [lindex $code 2]
    }
    # handle other types of failure here...
}

To get the status in 8.4, use this:

fconfigure $process -blocking 1
if {[catch {close $process}] == 1} {
    set code $::errorCode
    if {[lindex $code 0] eq "CHILDSTATUS"} {
        return [lindex $code 2]
    }
    # handle other types of failure here...
}

Upvotes: 3

Related Questions