Redirection / Passing back info to father shell

Redirection / Passing back info to father shell

Post by Nitzan Shak » Fri, 23 Apr 2004 04:44:58



Hi newsgroup

I need to execute 'command1 | command2' and get the exit status of
command1. I did my googling first, and came up with this:

( ( (command1 >&3 2>&3 ; echo $? >&4) 3>&1 | \
command2 >&3) 4>&1 | exit `cat`) 3>&1

I must admit I am at a loss. What are fd's 3 and 4? Does the construct

Quote:>&4 make 4 a duplicate of 1, or 1 a duplicate of 4? Can anyone explain

the lines above please?

There were other variations, but all involved temporary files which
are not elegant. I myself came up with one of those:

{ { command1 ; echo $? > TMP_FILE ; } | command2 ; } ; EC=`cat
TMP_FILE` ;\
rm TMP_FILE ; exit $(EC)

... but that's less elegant, again. *** However, I was wondering
whether there was ANY way (other than files) to communicate info from
a subshell to the parent shell.

I'm asking because command1 is executed in a subshell (a different
process) because of the pipe. Whatever I set there (variables) won't
be visible to the shell executing the pipe.

But since the shell can pass variables (export) to it's subshells, it
makes sense that they can return info in some manner. I could use that
to carry out the exit status.

tia
-- Nitzan

 
 
 

Redirection / Passing back info to father shell

Post by Icarus Sparr » Fri, 23 Apr 2004 19:32:37



> Hi newsgroup

> I need to execute 'command1 | command2' and get the exit status of
> command1. I did my googling first, and came up with this:

> ( ( (command1 >&3 2>&3 ; echo $? >&4) 3>&1 | \
> command2 >&3) 4>&1 | exit `cat`) 3>&1

> I must admit I am at a loss. What are fd's 3 and 4? Does the construct
>>&4 make 4 a duplicate of 1, or 1 a duplicate of 4? Can anyone explain
> the lines above please?

There is an explanation in the "CSH PROGRAMMING CONSIDERED HARMFUL" FAQ of
one way of doing it.
        >&4 makes stdout a duplicate of file descriptor 4.
Things you need to know are that file descriptor manipulation is done left
to right, but that pipes are done before fd manipulation.
So the first thing that is done is fd 3 is set up as a duplicate of the
original stdout, and then a subshell is started to run
( (command1 >&3 2>&3 ; echo $? >&4) 3>&1 | \
        command2 >&3) 4>&1 | exit `cat`
This sets up a pipe. The RHS of the pipe is easy, it is just
        exit `cat`
so it reads from its standard input a value and then exits with it. The
LHS is now
( (command1 >&3 2>&3 ; echo $? >&4) 3>&1 | command2 >&3) 4>&1
with stdout (fd 1) going to the pipe. Remember that fd 3 is a duplicate of
the original stdout. So this sets up fd 4 as a duplicate of the pipe going
to exit `cat`, and runs another subshell.
(command1 >&3 2>&3 ; echo $? >&4) 3>&1 | command2 >&3
This sets up a pipe. The RHS is easy, it is just
        command2 >&3
which runs command2 with its output going to fd 3, which is a duplicate of
the original stdout (fd 1). In other words this is making sure that the
output of command2 goes to the same place that it would have done if you
had just run
        command1 | command2
The LHS is now
        (command1 >&3 2>&3 ; echo $? >&4) 3>&1
with fd 4 going to the pipe to exit `cat`, and stdout (fd 1) going to
command2. It happens that fd 3 at this point is a duplicate of the
original stdout. Things are then overly complicated. It makes fd 3 a
duplicate of fd 1, the pipe to command2, and starts another subshell.
        command1 >&3 2>&3 ; echo $? >&4
This runs command1, sending its standard output (fd 1) and standard error
(fd 2) to fd 3, the pipe to command2. It then echos the exit status of
command1 to  fd 4, the pipe to exit `cat`.

So to answer your question "what is fd 4?" it is the pipe to the exit
command. "what is fd 3?" is either the original standard output of the
original, OR is a duplicate of the pipe to command2, depending on where it
is.

( ( (command1 2>&1 ; echo $? >&4) | command2 >&3) 4>&1 | exit `cat`) 3>&1
should do the same thing as
        command1 2>&1 | command2
except for the exit status stuff. Normally one doesn't want to send stderr
from command1 to command2, unless command2 is something like 'more',
'less', 'pg' or 'lp'.

Quote:> There were other variations, but all involved temporary files which are
> not elegant. I myself came up with one of those:

> { { command1 ; echo $? > TMP_FILE ; } | command2 ; } ; EC=`cat TMP_FILE`
> ;\
> rm TMP_FILE ; exit $(EC)

> ... but that's less elegant, again. *** However, I was wondering whether
> there was ANY way (other than files) to communicate info from a subshell
> to the parent shell.

The other ways are via the exit status and file descriptors. Using
command substitution either backticks or $( ) is a special case of file
descriptors. If you are using 'rc' or a modern version of 'bash' there is
the '$status' (for rc) or '$PIPESTATUS' (for bash) variables which makes
your life much simpler. e.g.

#!/bin/bash
command1 | command2
exit ${PIPESTATUS[0]}

Quote:> I'm asking because command1 is executed in a subshell (a different
> process) because of the pipe. Whatever I set there (variables) won't be
> visible to the shell executing the pipe.

True

Quote:> But since the shell can pass variables (export) to it's subshells, it
> makes sense that they can return info in some manner. I could use that
> to carry out the exit status.

It may make sense to you, but that is not how Unix works! It is based on a
system call 'fork' which makes a copy of a process. The fact that it is a
copy, and eventually the copy calls 'exit' and is then thrown away means
that there is no backward channel for data to flow.

 
 
 

1. Passing variables to the father process

Hello,

I've following code:

#!/usr/bin/ksh
FILENAME=`basename $0`
APPLI="global"
GLBEXE=/PROD/global/exe
APPEXE=/PROD/${APPLI}/exe
# Call cadump_sybase now
${GLBEXE}/cadump_sybase par1 par2
if [[ $? != "0" ]]; then
  wtor -t error -m "${Msg}"
  exit 1
fi

In this code I call the script cadump_sybase which executes
some commands and in case of error I want to return the
value of ${Msg} to the father process.

Excerpts of the cadump_sybase script:

#!/usr/bin/ksh
dump database to device .....
if [[ $? != "0" ]]; then
  Msg=" ${FILENAME}: Error occured during dump of database!"
  export Msg  
  exit 2
fi

The return value of the variable ${Msg} to the father process
is in every case "" and I don't want this script to be executed
inline i.e . ${GLBEXE}/cadump_sybase par1 par2.

Can someone tell me how to do this in another way as described
above?

Many thanks,

Lauer Edi

2. Printer

3. pass back return value to C program from Bourne shell?

4. Linux PPP connection

5. Passing Variables back to the shell

6. tape drive help

7. passing environment variables BACK to invoking shell

8. Unix vs Windows NT for faxing

9. How to pass a variable from a shell script to another shell script...

10. passing command with redirection to bash

11. Can I get back stdout after redirection?

12. pass values back to parent sell

13. Passing values generated in awk/nawk back to script