Cool. Thanks for sharing that.

On Fri, Jul 5, 2024 at 21:33 Adam Thompson <athompso@athompso.net> wrote:

I think I figured it out…

 

Command substitution ( $(cmd) or `cmd`) redirects the inner command’s stdout and captures it – that’s the whole point of command substitution.

So if I want dialog(1) to talk to the outer shell’s stdout without being captured by command substitution, I have to

  1. tell dialog(1) to send its results to stderr – this is the default
  2. redirect that diaglog(1) process’s stderr to FD 1 (stdout) using the inner shell
  3. redirect that dialog(1) process’s stdout to FD 3, which is the original, outer shell’s stdout, not the captured-by-command-substitution version of stdout.

Ugh.

 

-Adam

 

 

From: Roundtable <roundtable-bounces@muug.ca> On Behalf Of Adam Thompson
Sent: Thursday, July 4, 2024 9:01 PM
To: MUUG Roundtable <roundtable@muug.ca>
Subject: [RndTbl] dialog(1) shell fd acrobatics question

 

I’m trying to debug a shell script that uses dialog(1), which has the unfortunate habit of overwriting the debug output I wanted to see.

After quite some time banging my head against the wall, I grabbed the source to dialog to look at their examples.

 

Their examples follow a pattern I have NOT been following; I’m now looking at this trying to understand WTF it does:

 

1             exec 3>&1

2             returntext=`$DIALOG --title "RANGE BOX" --rangebox "Please set the volume..." 0 60 0 123 5 2>&1 1>&3`

3             returncode=$?

4             exec 3>&-

 

so… ok. 

Line 1 duplicates FD 1 (stdout) into FD 3.  That’s usually so we can mess with FD 1 later on and still have a handle to stdout.  Good so far.

Line 2 runs /usr/bin/dialog in a subshell, the options to dialog(1) are irrelevant here.  I’m looking at the redirects. 

    “2>&1” duplicates FD 1 into FD 2, effectively throwing away the handle to the inherited /dev/stderr and forcing stderr output onto stdout.  That’s a good thing because dialog(1) reports its results onto stderr by default to avoid messing with curses(3) output.

    “1>&3” however, throws away stdout (FD 1), replacing it with FD 3 which is… already a copy of FD 1 ???

Line 3 is obvious.

Line 4 closes FD 3.  Not sure that we need to bother, but OK, cleaning up behind ourselves is usually a good thing.

 

I get the need for swapping stdin/stderr, as dialog(1) – well, really curses(3) - uses stdout to paint the screen, so dialog(1) spits its results out on stderr to avoid conflicting.  If we’re in a subshell trying to capture that output, we need to grab it just as dialog(1) exits – and $() assignment only captures stdout.

 

But what’s the point of having FD 3 in this setup, if all we do is assign it to stdin inside the subshell and then forget about it?

 

Can anyone see what I’m missing here?

-Adam

 

_______________________________________________
Roundtable mailing list
Roundtable@muug.ca
https://muug.ca/mailman/listinfo/roundtable