Get the return code of the process created by open in TCL
Asked Answered
M

2

5

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?

Mb answered 10/1, 2019 at 10:17 Comment(0)
P
4

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
Polluted answered 10/1, 2019 at 11:31 Comment(1)
That was the information I needed. Unfortunately I can't use your example since try was implemented in tcl version 8.6 and I'm forced to use version 8.5 (which I totally forgot to mention). So I'll edit your answer and insert an example based on catch as well.Mb
E
3

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...
}
Earthstar answered 10/1, 2019 at 14:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.