kornシェルから返品ステータスをキャプチャし、同時にteeを使用する方法は? [コピー]

kornシェルから返品ステータスをキャプチャし、同時にteeを使用する方法は? [コピー]

ソースコードを考えてみましょう:

1.親.sh

#!/usr/bin/ksh
# No tee
ksh Child.sh;
exit_status=$?;
echo "Exit status: ${exit_status}"
# Using tee
ksh Child.sh | tee -a log.txt;
exit_status=$?;
echo "Exit status: ${exit_status}"

2.子供.sh

#!/usr/bin/ksh
...
exit 1;

出力:

Exit status: 1
Exit status: 0

  • 変数は$exit_statusChild.shの終了ステータスをキャプチャするためです1
  • 2番目のケースでは、$exit_statusティーの終了ステータスがキャプチャされます0

もしそうなら、終了ステータスをキャプチャしてteeを使用する方法は?

ベストアンサー1

再印刷(および改善)comp.unix.shell FAQ(私はFAQのこの部分を書いたからです):

cmd1 | cmd2からcmd1の終了コードを取得する方法

まず、cmd1の終了コードがゼロではないかもしれませんが、これはエラーを意味しません。たとえば、このような場合が発生します。

cmd | head -n 1

141(またはksh93の場合は269、yashの場合は397)の終了状態を見ることができますが、cmdこれは1行を読んだ後に終了するのがcmdSIGPIPE信号によって中断されたためです。head -n 1

パイプライン要素の終了状態を理解する

cmd1 | cmd2 | cmd3

zsh(およびFish 3.1+)を使用する:

終了コードは特別な配列で提供されますpipestatuscmd1終了コードはin$pipestatus[1]cmd3終了コードはin $pipestatus[3]なので、$status/は$?常にと同じです $pipestatus[-1]

バッシュと一緒に:

終了コードは特別な配列で提供されますPIPESTATUS。終了コードはにあるので、 cmd1常に(または4.2より前のバージョンの場合)同じです。${PIPESTATUS[0]}cmd3${PIPESTATUS[2]}$?${PIPESTATUS[-1]}${PIPESTATUS[@]: -1}

他のBourne型シェルと同様に

終了コードをデフォルトのシェルに渡すには、トリックを使用する必要があります。これはパイプ(2)を使用して行うことができます。実行するのではなく、cmd1実行してcmd1; echo "$?"$?がシェルに入っていることを確認します。

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"

$ec1、、、$ec2の終了コードです$ec3

POSIX シェルの使用

この機能により、作業を簡単に行うことができます。

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"
}

次のように使用してください。

run cmd1 \| cmd2 \| cmd3

終了コードは$pipestatus_1$pipestatus_2、 にあり、一番右のゼロ以外の終了状態$pipestatus_3です (一部のシェルオプションと同様)。$?pipefail

おすすめ記事