Bash: Eval & Tee: 出力の実行方法、出力のキャプチャ、エラーの確認方法

Bash: Eval & Tee: 出力の実行方法、出力のキャプチャ、エラーの確認方法

Ubuntu 16.04を使用して#!/bin/bash評価されたコマンドが必要です。

  • 直接出力を提供
  • 出力を変数にインポートする
  • 評価結果の確認
# valid command
foo=$(eval "ls" | tee /dev/tty);
echo ${PIPESTATUS[@]}
echo $foo

# invalid command
foo=$(eval "ls -ßnonsense" | tee /dev/tty);
echo ${PIPESTATUS[@]}
echo $foo

PIPESTATUS私の問題は意味のある結果を得たとき

  • 完全に削除しましたtee /dev/tty(それ以外の場合は、最初のパイプラインコマンドの一部としてすべての評価失敗をマスクします)。
  • または括弧の外に入れてくださいfoo=$(eval "ls" ) | tee /dev/tty;- ...しかし、この場合、もはや直接出力または$ foo出力を取得できません。

答え1

代わりに使用してくださいzsh

shell_code='ls' # or ls -ßnonsense...
{ foo=$(eval " $shell_code" >&1 >&3 3>&-); } 3>&1
print -r status=$? output=$foo

ここでは、元のstdout(スクリプトがリダイレクトなしで端末で実行されている場合は制御ttyのみ)をfd 3にコピーし、出力をコマンド置換とfd eval3にリダイレクトしますtee使用)。 。

サポートされている他のシェル(Linux / Cygwinではksh93ではありません)があるシステムでは、bash次のことができます。pipefail/dev/fd/<n>

shell_code='ls' # or ls -ßnonsense...
{
  foo=$(
    set -o pipefail
    eval " $shell_code" 3>&- | 
      tee 4>&1 >&3 3>&- /dev/fd/4
  )
} 3>&1

printf 'status=%s output=%s\n' "$?" "$foo"

open の場合、pipefailパイプの終了状態は、パイプで失敗した一番右のコマンドの終了状態です。失敗しないeval限り、ここにありますtee

eval無条件の終了ステータスを取得するには、次のものをbash使用できます。

shell_code='ls' # or ls -ßnonsense...
{
  foo=$(
    eval " $shell_code" 3>&- |
      tee 4>&1 >&3 3>&- /dev/fd/4
    exit "$PIPESTATUS"
  )
} 3>&1

printf 'status=%s output=%s\n' "$?" "$foo"

これらの方法では、teestdoutは生のstdoutであり、コマンド置換はパイプを介して提供されます/dev/fd/4。私たちは別の方法(teeコマンド代替パイプにstdoutを送信し、いくつかのコマンドを介して元のstdoutに書き込む/dev/fd/<n>)の代わりにこれを行います。これにより、コードがより複雑になりますが、後者がLinuxで動作しないことを避けます。あるいは、Cygwinシステムで開くことは/dev/fd/<n>fdをコピーするのと同じではありません<n>(ただし、コマンドの置き換え(ソケットペアを使用するksh93ではない)などのパイプの書き込みの終わりを指すfdに対してこれを行うことは機能的に同じです) 。

答え2

bashこれは、、、、、(Bourne)および次にテストされたほとんどの(すべてではありdashませんが)Bourne構文シェルで動作する移植可能なソリューションです。ksh93ksh88ashshzsh

for command in "ls -ßnonsense" "ls -ld /tmp"; do
    foo=`{ eval "$command"; echo $? > /tmp/ps.$$; } | tee /dev/tty;`
    st=`cat /tmp/ps.$$;rm /tmp/ps.$$`
    echo "foo=$foo status=$st"
done

関連情報