- John
Why do you care ? The answer to this may lead to a better-fit reply...
-Alex
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.
#!/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
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
}
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