いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

標準出力と標準エラー出力にリダイレクトしながら出力をターミナルに表示 (bash, tee, process substitution)

f:id:gsf_zero1:20220201185442p:plain

概要

こんなやり方あるって知らなかったので、目からウロコでした。

忘れないうちにメモメモ。。。

stackoverflow.com

何かの出力を標準出力と標準エラー出力に分けてリダイレクトさせるのは以下で出来ます。

$ ./script.sh 1> stdout.log 2> stderr.log

このパターン、とても便利でよく利用しますが、ターミナルに情報は表示されなくなってしまいます。

リダイレクトしているので当たり前です。でも、見たいときがあります。

そのようなときは、以下のように bash の プロセス置換 (process substitution) と tee コマンドをあわせ技で使います。

$ ./script.sh 1> >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)

こうやると、ファイルに出力しつつ、teeコマンドによってターミナルにも出力されます。素晴らしい。

サンプル

以下のようなスクリプトがあるとします。データ出力用です。

#!/usr/bin/env bash

set -ue -o pipefail
export LC_ALL=C

echo 'stdout'
echo 'stderr' 1>&2

んで、以下のような実行スクリプトがあるとします。

#!/usr/bin/env bash

# https://moneyforward.com/engineers_blog/2015/05/21/bash-script-tips/
set -ue -o pipefail
export LC_ALL=C

# https://stackoverflow.com/questions/692000/how-do-i-write-stderr-to-a-file-while-using-tee-with-a-pipe
sh ./script.sh 1> >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)

後は、一応Makefile。

run:
   @chmod +x ./main.sh
   @./main.sh

confirm:
   @echo '--- STDOUT ---'
   @cat ./stdout.log
   @echo '--- STDERR ---'
   @cat ./stderr.log

clean:
  rm -f ./std*.log

んで、実行してみると

$ make run ; make confirm ; make clean
stdout
stderr
--- STDOUT ---
stdout
--- STDERR ---
stderr
rm -f ./std*.log

ちゃんとターミナルに出力しつつ、ファイルにも書き込めています。

参考情報

linux - How do I write stderr to a file while using "tee" with a pipe? - Stack Overflow

bash: 標準出力、標準エラー出力をファイル、画面それぞれに出力する方法 - Qiita


過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。