コマンドが成功した場合にのみ出力を抑制するにはどうすればよいですか?


22

通常成功するセカンダリコマンドの出力を抑制することにより、スクリプトの出力を単純化したいと思います。

ただし、-qそれらを使用すると、時々失敗するときに出力が非表示になるため、エラーを理解する方法がありません。さらに、これらのコマンドは出力をに記録しますstderr

成功した場合にのみコマンドの出力を抑制する方法はありますか?

たとえば、次のような(ただしこれに限定されません):

mycommand | fingerscrossed

すべてうまくいった場合fingerscrossed、出力をキャッチして破棄します。それ以外の場合は、標準出力またはエラー出力(何でも)にエコーします。

回答:


36

moreutils' chronicコマンドはそれを行います:

chronic mycommand

mycommand失敗しない限り、出力を飲み込みます。失敗しない場合、出力が表示されます。


1
ありがとうございました。ほとんどのUnix OSにはデフォルトでインストールされていないと思いますか?
マチューナポリ

1
おそらくそうではありませんが、広くパッケージ化されているため、簡単にインストールできます。
スティーブンキット

1
Debianにはパッケージに含まれていますmoreutils。私にとってニース、とにかく:)
トム・ザイッチ

6
出力全体をメモリに保存することに注意してください。
ステファンシャゼル

1
@StéphaneChazelasはおそらくこのようなものを実装する唯一の方法です。必要な場合に備えて、コマンドの実行中に出力を保存する必要があります。
-Centimane

11
### do this bit once at the top of your script
divert=
exec 3<>"${divert:=$(mktmp)}" 4<>/dev/null
rm -- "$divert"; unset divert
### then do this bit as often as needed
command >&3 2>&3
cat <&3 >&"$(((RTN=$?)?2:4))"

おそらくこれでうまくいくはずです。それぞれの出力をcommand削除された一時ファイルにバッファリングし、その後/dev/null、戻りステータスがゼロでないかどうかに応じて、出力をいずれかまたはstderrに吸い上げます。一時ファイルは事前に削除されているため、現在のシェルとそのファイル記述子の子以外のプロセスで読み取ることはできません/proc/$pid/fd適切な権限を持つ卑劣なスヌープを除きます)。また、終了時にクリーンアップする必要はありません。

おそらく、Linuxシステムでのより便利なソリューション:

divert(){
    "$@" >&3 2>&3 ||
    eval "cat <&3
          return $?"
}   3<<"" 3<>/dev/fd/3

...これは、ほとんどのシェルで、他のシェルとほとんど同じように機能しますが、次のように呼び出すことができますdivert some simple-command with args。中、高出力コマンドの用心"$@"のために、しかし、dashyash、またはパイプとヒアドキュメントの操作を行い、いくつかの他のシェル-私はそれがパイプのバッファを埋めるために、これらのシェルでは可能かもしれないと思う(linuxesの周りの128キロバイトのデフォルトでは)、デッドロックので、 。それはのために心配すべきではないkshmkshbashzsh、またはBourneシェル、しかし-それらのすべては、私がして上に明示的に行ったように基本的に同じことを行いますexec


9

通常、エラーの場合、コマンドはメッセージを出力するstderrため、タスクを抑制することができますstdout

mycommand > /dev/null


ありがとうございますが、質問で述べたように、コマンドはすべての出力を記録しますstderr(したがって、効果はありません)。
マチューナポリ

4

あなた自身の慢性を作るために

my_chronic() {
  tmp=$(mktemp) || return # this will be the temp file w/ the output
  "$@"  > "$tmp" 2>&1 # this should run the command, respecting all arguments
  ret=$?
  [ "$ret" -eq 0 ] || cat "$tmp"  # if $? (the return of the last run command) is not zero, cat the temp file
  rm -f "$tmp"
  return "$ret" # return the exit status of the command
}

3

メイクファイルで次のようなことを行います。

if (mycommand) &> mycommand.log; then 
  echo success 
else 
  c=$?; 
  echo;echo -e "Bad result from previous command, see mycommand.log for more details";echo;
  command_to_run_on_fail
  (exit $c)
fi

それをあなたの状況に合わせて、次のようなことができます:

if ! (mycommand) &> mycommand.log; then 
  c=$?; 
  cat mycommand.log
  rm mycommand.log
  (exit $c)
fi

したがって、「if」はコマンドを実行し、出力をmycommand.logにパイプします。stdout vs stdout vs anythingをキャッチする必要がある場合は、パイプコマンド「&>」を「>」に変更する必要があります。コマンドが失敗した場合は、エラーコードをキャプチャし、mycommand.logの内容を出力し、mycommand.logを削除して、最後に元のエラーコードを返します。

(exit $ c)がなければ、「rm」コマンドが返したものと一致する終了コードで戻ります。

最後に、1つのライナーが必要な場合は、このようなものが機能します。

mycommand &> mycommand.log || cat mycommand.log; rm mycommand.log

2
コマンドなどを本当にラップしますか。で(...)そのような?なぜなら、それはあなたにとって有用なことは何もしないが、余分なサブシェルを生成するからです。
エタンライスナー

@EtanReisner (exit $c)はsettingです$?。これは他の方法ではできません。if ! (mycommand) &>xコマンドが例えばを使用するtimeか、シェルエラーを与える場合、リダイレクトで意味があります。
マイケル・ホーマー

@MichaelHomer-これらのものにはカーリーがあり{ ; }ます...確かにexitそこには少し難しいです。
mikeserv

makefileスニペットでは、以前に保存したもので終了しようとしている$?場合はそのまま使用できますexit $cが、はい、他の場合に(exit $?)は値があります(シェル関数のrret() { return $1; }方が一般的には良いと思います)。mikeservが示したように、コマンドのサブシェルはまだ実際には動作しません。
エタンライスナー

3

私はこの他の質問でこれほど簡単な答えを見つけました:

output=`mycommand 2>&1` || echo $output

チャームのように機能します!


注:私のユースケースでは、これははるかに単純なソリューションでした(すべてのCIサーバーに余分なものをインストールすることを避けます)ため、この1つを承認済みとしてマークすることを選択しました。YMMV。
マチューナポリ

シェルスクリプトでset -o xtraceを使用すると、割り当てoutput = ...の詳細のロギングの一部として、すべての出力が再び出力されることに注意してください。その場合は、おそらく慢性を使用する方が良いでしょう。
Jan-Philip Gehrcke
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.