ret val of a command in a pipe which is NOT the last one

hello dear UNIX gurus :wink:

my problem is one of those i would think that many others should also have had it in the past. but i cannot find any thread or other documentation about it.

inside a ksh script i have a pipe like this:

ksh -c "export LIBPATH=$LD_LIBRARY_PATH; ${Cmd} ${Param} 2>&1 | tee -a ${LogFile}"

now i need to return the return value of ${Cmd} to the caller. as everybody knows, the $? gives me the ret val of the tee call, which is not important here. nevetheless i want to use the tee feature here. many this-style pipes can be usefull.

i have tried workarounds with

[[ ! -r ${LogFile} ]] && touch ${LogFile}
tail -f ${LogFile} &
TAILPID=$!
ksh -c "export LIBPATH=$LD_LIBRARY_PATH; ${Cmd} ${Rest} >> ${LogFile} 2>&1"
RET=$?
sleep 5
kill -9 ${TAILPID} > /dev/null 2>&1

exit ${RET}

but i think there must be a better solution, maybe using file descriptors greater than2. but i did not succeed yet :frowning:

has anybody an idea?

this would be great

thank you all and bye bye

latze

I don't understand why you are invoking an explicit subshell here, nor why you would use "ksh -c" to invoke it. I'm guessing that you don't want to change the script's current definition of LIBPATH. Assuming that to be an absolute requirement, you can do this:

exec 4>&1 5>&2
tee -a ${LogFile} >&4 |&
exec >&p 2>&1
(export LIBPATH=$X ; eval exec ${Cmd} ${param})
RET=$?
exec >&4 2>&5
echo RET = $RET

This is perhaps even more convoluted than your work-around. But it eliminates that "tail -f" and returns to the "tee" command. And it also eliminates the race condition from your sleep/kill commands. If the subshell is not needed, you should replace it with:
export LIBPATH=$X
eval ${Cmd} ${param}

thanks for this perfect solution. i'm not that UNIX guru, so i must admit that i will need some days to really understand it. but i will take that time because i feel that dealing with file descriptors may give me new dimensions of UNIX programming. thanx very very much :slight_smile:

hello Perderabo,

i've tried to understand your excellent code. i do not understand why you use the extra file descriptors 4 and 5. i think this code fragment should do the same job:

tee -a ${LogFile} |&
exec 2>&1
(export LIBPATH=$LD_LIBRARY_PATH; eval exec ${Cmd} ${Rest})
RET=$?

because the tee command has already the same STDIN and STDOUT as the parent. the basic idea is to put the tee in the background with a bidirectional pipe, waiting for input from the parent, isn't it?

Try your code fragment. The tee process will never write to the logfile. It *might* recreate the logfile if it doesn't exist. Other than that it clearly will do nothing.

A co-process certainly does not use the same file descriptors as the main process. That would render it useless.

These days pipes pretty much are bidirectional. And with some use of the ksh <> construct it might be possible to exploit this. But I never do. Each fd that I use in a script is for reading only or writing only. I always assume pipes to be unidirectional.

The first exec saves the current stdout and stderr so that the last exec can restore them. The stuff in between connects the output from the subshell to the input of the co-process and the output of the co-process to the original output.

thank you very much !!