7

Let's say I do this in a unix shell

$ some-script.sh | grep mytext

$ echo $?

this will give me the exit code of grep

but how can I get the exit code of some-script.sh

EDIT

Assume that the pipe operation is immutable. ie, I can not break it apart and run the two commands seperately

Mike
  • 58,961
  • 76
  • 175
  • 221

5 Answers5

5

There are multiple solutions, it depends on what you want to do exactly.

The easiest and understandable way would be to send the output to a file, then grep for it after saving the exit code:

tmpfile=$(mktemp)
./some-script.sh > $tmpfile
retval=$?
grep mytext $tmpfile
rm tmpfile
watain
  • 4,838
  • 4
  • 34
  • 35
  • 3
    I see. Maybe that's a solution: `tmpfile=$(mktemp); (./some-script.sh; echo $? > $tmpfile) | grep mytext; retval=$(cat $tmpfile)`. That's quite dirty, but maybe it helps. – watain May 17 '10 at 18:35
  • then grep gets the output of `echo $? > tmpfile` – Mike May 17 '10 at 18:43
  • No, because `echo $? > $tmpfile` has no output. The standard output of `echo` is sent to `$tmpfile`. – watain May 17 '10 at 18:47
  • right, and that nothing gets passed to grep, it doesn't append the output of the first command – Mike May 17 '10 at 18:48
  • I'm not sure if I understood that correctly. The output of the first command (`./some-script.sh`) still reaches grep. Have you tried it? Maybe you could add the actual script with the problem and why the pipe operation is immutable. – watain May 17 '10 at 18:57
4

A trick from the comp.unix.shell FAQ (#13) explains how using the pipeline in the Bourne shell should help accomplish what you want:

   You need to use a trick to pass the exit codes to the main
   shell.  You can do it using a pipe(2). Instead of running
   "cmd1", you run "cmd1; echo $?" and make sure $? makes it way
   to the shell.

   exec 3>&1
   eval `
     # now, inside the `...`, fd4 goes to the pipe
     # whose other end is read and passed to eval;
     # fd1 is the normal standard output preserved
     # the line before with exec 3>&1
     exec 4>&1 >&3 3>&- 
     {
       cmd1 4>&-; echo "ec1=$?;" >&4
     } | {
       cmd2 4>&-; echo "ec2=$?;" >&4
     } | cmd3
     echo "ec3=$?;" >&4
jmlane
  • 2,109
  • 1
  • 16
  • 24
2

There is a utility named mispipe which is part of the moreutils package.

It does exactly that: mispipe some-script.sh 'grep mytext'

Bakuriu
  • 98,325
  • 22
  • 197
  • 231
someone
  • 21
  • 1
2

If you're using bash:

PIPESTATUS
    An array variable (see Arrays) containing a list of exit status values from the processes in the most-recently-executed foreground pipeline (which may contain only a single command). 
Randy Proctor
  • 7,396
  • 3
  • 25
  • 26
0

First approach, temporarly save exit status in some file. This cause you must create subshell using braces:

(your_script.sh.pl.others; echo $? >/tmp/myerr)|\ #subshell with exitcode saving
grep sh #next piped commands
exitcode=$(cat /tmp/myerr) #restore saved exitcode
echo $exitcode  #and print them

another approach presented by Randy above, simplier code implementation:

some-script.sh | grep mytext
echo ${PIPESTATUS[0]} #print exitcode for first commands. tables are indexted from 0

its all. both works under bash (i know, bashizm). good luck :) both approaches does not save temporarly pipe to physical file, only exit code.

Znik
  • 1,047
  • 12
  • 17