Capturing file descriptor 3, or alternatives.

Ben Scott dragonhawk at gmail.com
Thu Jul 5 00:39:56 EDT 2012


  I just realized I replied privately and not to the list on the below.  D'oh!

---------- Forwarded message ----------
From: Ben Scott
Date: Sun, Jun 24, 2012 at 9:49 PM
Subject: Re: Capturing file descriptor 3, or alternatives.
To: Bill Freeman

On Tue, Jun 19, 2012 at 4:34 PM, Bill Freeman <ke1g.nh at gmail.com> wrote:
> I really hate string processing in bash.  So I'd like to write a
> script in another language that 1. interacts with the user; 2.
> calculates the desired values of some environment variables; and 3.
> communicates those settings to the shell from which it was invoked
> (since the environment variables are for other programs to be started
> by that shell in the future).

  One possible alternative approach is to break those steps up into
smaller chunks, and have the shell script control each chunk.  Then
you could use, e.g., dialog(1) to prompt the user, and
sed/awk/Perl/whatever to do the string processing.

  I gather this is not your envisioned solution, but if your
controller is going to be a shell script, then it makes sense to put
control in hands of the shell script.  If you'd really rather not the
shell script be in control, then maybe you shouldn't be using a shell
script.  :)  Most other languages have facilities for setting
environment variables and spawning children.  Of course, if your shell
script is a 5000 line blob of existing code, this is likely not
practical, but I wanted to mention it.

> I can't just use back-tick and print the information because I need
> standard out so that I can print a menu and other prompts to the user.

  dialog(1) has an option to send its result to stdout, which causes
it to open the tty directly for the UI.  The drawback is it's less
portable and may fail miserably on some systems, but if high
portability is not a concern, you can do:

        ANSWER=$(dialog --stdout --title 'Moria' --inputbox 'Speak, Friend,
and enter' 0 0 )

  This works on my Debian 6.0 box, and a CentOS 5.8 box at work.
That's a whole two test cases -- proof it works everywhere!  ;-)

  Some Google searching found this method:

        ANSWER=$(dialog --title 'Moria' --inputbox 'Speak, Friend, and enter'
0 0 3>&1 1>&2 2>&3 3>&- )

  That swaps file descriptors around, so that dialog runs with it's
idea of stderr attached to the shell's idea of stdout, and vice versa.
 Specifically, it dupes stdout 1 to 3 (as a temporary holding spot),
then dupes stderr 2 to 1, then temporary stdout 3 to 2, then closes
temporary 3.  I got this idea from:

http://stackoverflow.com/questions/1970180/whiptail-how-to-redirect-output-to-environment-variable

  The only downside to this is legitimate errors from dialog(1) may
end up in your variable instead.

  While I'm using dialog(1) in these examples, if your other script
does user interaction on stdout and writes shell variable assignments
on stderr, I think this would work:

        eval $( other_script 3>&1 1>&2 2>&3 3>&- )

> What occurred to me is to send the final result to fd 3, which the
> shell would have to have opened before forking.

  Hmmm.  Seems like that should be possible.  There are a bunch of
ways in bash to play with file descriptors and I/O streams.  And
dialog(1) (to continue my example) has an --output-fd= switch to
specify any file descriptor number for result output.

  I think you might be able to arrange this with some combination of

* redirection of exec without arguments to change the shell's file own
descriptors
* {varname} redirection to open new file descriptors
* redirection referencing file descriptors (/dev/fd/* syntax)

but I can't figure out how.  I tried this unholy mess

        exec {REAL_STDIN}<&0
        exec {OOB}<&0
        exec {REAL_STDOUT}>&1
        ANSWER=$(dialog --output-fd $OOB --title 'Moria' --inputbox 'Speak,
Friend, and enter' 0 0 </dev/fd/$REAL_STDIN >/dev/fd/$REAL_STDOUT )

and dialog seemed to run okay but $ANSWER was empty afterwards.

  Let me know if you ever figure this out.  :-)

-- Ben


More information about the gnhlug-discuss mailing list