How do I capture the return status and use tee at the same time in korn shell?

Reproduced (and improved) from the comp.unix.shell FAQ (since I happen to have written that section of the FAQ):

How do I get the exit code of cmd1 in cmd1|cmd2

First, note that cmd1 exit code could be non-zero and still don't mean an error. This happens for instance in

cmd | head -n 1

you might observe a 141 (or 269 with ksh93, or 397 with yash) exit status of cmd, but it's because cmd was interrupted by a SIGPIPE signal when head -n 1 terminated after having read one line.

To know the exit status of the elements of a pipeline

cmd1 | cmd2 | cmd3

with zsh (and fish 3.1+):

The exit codes are provided in the pipestatus special array. cmd1 exit code is in $pipestatus[1], cmd3 exit code in $pipestatus[3], so that $status/$? is always the same as $pipestatus[-1].

with bash:

The exit codes are provided in the PIPESTATUS special array. cmd1 exit code is in ${PIPESTATUS[0]}, cmd3 exit code in ${PIPESTATUS[2]}, so that $? is always the same as ${PIPESTATUS[-1]} (or ${PIPESTATUS[@]: -1} for versions older than 4.2).

with any other Bourne like shells

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 its way to the shell.

exec 3>&1
code=`
  # now, inside the backticks, fd4 goes to the pipe
  # whose other end is read and stored in $code  for
  # later evaluation; 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 4>&-
  echo "ec3=$?;" >&4
`
exec 3>&-
eval "$code"

Exit codes in $ec1, $ec2, $ec3.

with a POSIX shell

You can use this function to make it easier:

run() {
  j=1
  while eval "\${pipestatus_$j+:} false"; do
    unset "pipestatus_$j"
    j=$(($j+1))
  done
  j=1 com= k=1 l=
  for arg do
    case $arg in
      ('|')
        com="$com {
               $l "'3>&-
               echo "pipestatus_'$j'=$?" >&3
             } 4>&- |'
        j=$(($j+1)) l=;;
      (*)
        l="$l \"\${$k}\""
    esac
    k=$(($k+1))
  done
  com="$com $l"' 3>&- >&4 4>&-
       echo "pipestatus_'$j'=$?"'

  { eval "$(exec 3>&1; eval "$com")"; } 4>&1
  j=1
  ret=0
  while eval "\${pipestatus_$j+:} false"; do
    eval '[ "$pipestatus_'"$j"'" -eq 0 ] || ret=$pipestatus_'"$j"
    j=$(($j+1))
  done
  return "$ret"
}

Use it as:

run cmd1 \| cmd2 \| cmd3

exit codes are in $pipestatus_1, $pipestatus_2, $pipestatus_3 and $? is the right-most non-zero exit status (like with the pipefail option of some shells).