Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Expect: how to tell if stdin is redirected from /dev/null?

232 views
Skip to first unread message

John Caruso

unread,
Nov 23, 2007, 6:55:39 PM11/23/07
to
In expect (5.43.0), is there any way to tell if stdin has been redirected
from /dev/null? I.e., what would the code be to differentiate running
myscript without input redirected and running "myscript < /dev/null"?

- John

Alexandre Ferrieux

unread,
Nov 24, 2007, 6:34:50 AM11/24/07
to
On Nov 24, 12:55 am, John Caruso <johnSPAMcarAWAY...@myprivacy.ca>
wrote:

> In expect (5.43.0), is there any way to tell if stdin has been redirected
> from /dev/null? I.e., what would the code be to differentiate running
> myscript without input redirected and running "myscript < /dev/null"?

Why do you care ? The answer to this may lead to a better-fit reply...

-Alex

Donal K. Fellows

unread,
Nov 24, 2007, 8:51:27 AM11/24/07
to

On Linux, you can use [file readlink /proc/[pid]/fd/0] to find out
what stdin really is. That might or might not help. :-)

Donal.

Uwe Klein

unread,
Nov 24, 2007, 11:15:09 AM11/24/07
to

#!/usr/bin/expect

if {[ catch {fconfigure stdin -mode} cerr]} {
puts stderr "stdin is not a tty : $cerr"
read stdin 1
if {[eof stdin]} {
puts stderr "stdin could be /dev/null"
}
} else {
puts stderr "stdin is a tty : $cerr"
}

# end

the -mode test will not differentiate between
a real tty and and a (faked) pty
seeking on a pipe is a catchable error.
seeking on /dev/null is ok
but you are at eof if you read 1 byte

uwe

John Caruso

unread,
Nov 24, 2007, 1:11:35 PM11/24/07
to
On 2007-11-24, Uwe Klein <uwe_klein_...@t-online.de> wrote:
> John Caruso wrote:
>> In expect (5.43.0), is there any way to tell if stdin has been redirected
>> from /dev/null? I.e., what would the code be to differentiate running
>> myscript without input redirected and running "myscript < /dev/null"?
>>
>> - John
>
> #!/usr/bin/expect
>
> if {[ catch {fconfigure stdin -mode} cerr]} {
> puts stderr "stdin is not a tty : $cerr"
> read stdin 1
> if {[eof stdin]} {
> puts stderr "stdin could be /dev/null"
> }
>} else {
> puts stderr "stdin is a tty : $cerr"
>}

Perfect, many thanks. In fact I was really looking for an isatty function
(just as you've provided), but I didn't want to ask the question in those
words since I didn't want to constrain the solution. It's a bit surprising
that expect doesn't provide one.

For those wondering why: I have an expect script (below) that exhibits bad
behavior when it's run with input redirected from /dev/null, apparently
caused by the interact statement handling EOF (if a preceding expect
statement sees the EOF, all's well). BTW, this is a minimal test script
culled from a much longer script, which is the reason for some of the odd
bits of code. Here are sample run lines:

./script --user test --hosts "host1 host2 host3" "date; sleep 2; id"
./script --rsh --hosts "filer1 filer2 filer3" "date; version"

The key is to specify multiple hosts, which causes the script to spawn
multiple remote sessions (you'll need to have trust relationships with
the remote hosts for this version of the script, and you can specify a
single host multiple times). When the script is run with input coming
from the tty it behaves fine, but when it's run with input redirected from
/dev/null it will do one of the following after the 2nd or 3rd host:

1) "error writing "stdout": invalid argument
while executing
"puts -nonewline $savedoutput"
2) "interact: spawn id exp0 not open" -- If the catch statement is removed
from the interact statement.

(In the first case it may also fail without producing the error message--
but it will also stop producing output, as though the puts statements are
having their output thrown away.)

The weirder failure mode is 1. In this case (with the catch protecting
the interact statement), it appears that merely calling interact with
stdin redirect from /dev/null causes *stdout* to be closed, which makes
the puts (or send_user, if you switch it out for that) fail. Is that the
expected behavior of interact? It certainly wasn't for me.

As I said, the difference in whether it produces the above error or not
appears to be whether or not the expect statement consumes the EOF from
the child. If it does, all's well, but if the EOF is still out there when
the interact statement is executed the script will die on the next host.

Anyway, your code will allow me to work around this issue (by never calling
interact if there's not a tty attached), but I'd certainly be interested
to hear if anyone has an idea of why calling interact would cause stdout
to be closed.

- John

#!/usr/bin/expect --

set hosts ""
set remotecommand "ssh"
set user "root"

while {[llength $argv] > 0} {
switch -regexp -- [lindex $argv 0] {
^--(h|ho|hos|host|hosts)$ {
append hosts " " [lindex $argv 1]
set argv [lrange $argv 1 end]
}
^--(r|rs|rsh)$ {
set remotecommand "rsh"
}
^--(u|us|use|user)$ {
set user [lindex $argv 1]
set argv [lrange $argv 1 end]
}
default {
break
}
}
set argv [lrange $argv 1 end]
}

send_user "DEBUG: hosts='$hosts', argv='$argv'\n"

foreach host $hosts {

log_user 0

eval spawn $remotecommand -l $user $host $argv

expect {
-re ".+" { }
}
set savedoutput "$expect_out(buffer)"

puts -nonewline "***** $remotecommand command output for $host *****\n"
puts -nonewline $savedoutput
interact
catch {
}

wait -nowait
}

John Caruso

unread,
Nov 24, 2007, 1:21:43 PM11/24/07
to
On 2007-11-24, John Caruso <johnSPAMc...@myprivacy.ca> wrote:
> puts -nonewline "***** $remotecommand command output for $host *****\n"
> puts -nonewline $savedoutput
> interact
> catch {
> }

This last bit should have been:

> catch {
> interact
> }

The first way (at the top) will cause failure mode 2, and this way will
cause the more interesting failure mode 1 (I was switching back and forth
during testing, and didn't notice that I'd left it this way).

I should have mentioned that I've seen this on expect 5.43.0 and 5.42.1,
and on Linux (RHEL4) and Solaris (8). The fact that stdout is somehow
closed feels like a bug; I can understand that interact wouldn't work
desirably when input is redirected from a file, but closing stdout was
pretty surprising behavior.

- John

0 new messages