tee コマンドのすすめ

環境構築
shellscript
作者

Ryo Nakagami

公開

2026-10-01

更新日

2026-10-13

ノートTL;DRs
やりたいこと 書き方
画面とファイルの両方に出す cmd | tee out.log
stderr も含める cmd 2>&1 | tee out.log
追記する cmd | tee -a out.log
複数ファイルに保存する cmd | tee a.log b.log
終了ステータスを保つ set -o pipefail または ${PIPESTATUS[0]}
色を残しつつログは素のテキストにする cmd --color=always 2>&1 | tee >(sed ... > out.log)
root 権限のファイルに書く echo ... | sudo tee -a file > /dev/null
Python の出力を即時表示する python -u script.py 2>&1 | tee out.log

tee コマンドとは

定義 1 tee コマンド

  • tee は標準入力から受け取った内容を,標準出力とファイルの両方に書き出すコマンド
  • ファイルへの保存と標準出力への出力を同時に行える
  • 複数のファイルへの出力も可能
コマンド1 | tee ファイル | コマンド2
コマンド | tee ファイル1 ファイル2 ファイル3 ...
短いオプション 長いオプション 意味
-a --append 既存ファイルを上書きせず追記する(リダイレクトの >> に相当)
-i --ignore-interrupts 割り込みシグナル(SIGINT)を無視する

「画面で進捗を見ながら,同じ内容をログとして残す」という,データ分析や開発で頻出する要求を1つのコマンドで満たせます.

リダイレクトとの違い

書き方 画面 ファイル
cmd > out.log 出ない 出る
cmd | tee out.log 出る 出る
cmd | tee -a out.log 出る 追記される

基本の使い方

例 1 (リダイレクトとパイプを同時に行う) コマンド > ファイル と コマンド | コマンド を同時に行いたい場合は,間に tee を挟みます.

find /bin /usr/bin -type f | tee cmdlist | less

find の結果を cmdlist に保存しつつ,less で閲覧しています.


例 2 (複数のファイルに保存する)  

ls | tee a.lst b.lst c.lst

tee は標準出力にも書き出すので,画面に出したくない場合は出力先の1つをリダイレクトにします.

ls | tee a.lst b.lst > c.lst

例 3 (stderr も一緒に残す) パイプが渡すのは stdout だけです.エラーメッセージや進捗表示は stderr に出ることが多いので,ログを取るときは 2>&1 でまとめてから tee に渡します.

cargo test --locked 2>&1 | tee test.log

cargo はビルドの進捗を stderr に,テスト結果を stdout に出すため,2>&1 がないとビルドログがファイルに残りません.


開発での使いどころ

終了ステータスを保持する

パイプにすると,終了コードは最後のコマンドである tee のもの(ほぼ常に 0)になります. テストが失敗してもスクリプトや CI が成功扱いになってしまうので,次のどちらかで対処します.

set -o pipefail
cargo test --locked 2>&1 | tee test.log
cargo test --locked 2>&1 | tee test.log
exit "${PIPESTATUS[0]}"
ノート
  • PIPESTATUS は bash の配列
  • zsh では小文字の pipestatus で,添字が1始まりになります(${pipestatus[1]}).

画面の色を残す

パイプ先は TTY ではないため,多くのコマンドは色を自動で無効にします. cargo の場合,cargo 本体とテストハーネスの両方に指定します.

cargo test --locked --color=always -- --color=always 2>&1 | tee test.log

ただしこの方法ではログにも ANSI エスケープが入ります. ログをプレーンテキストにしたい場合は,プロセス置換を使ってファイルに書く側だけで除去します.

cargo test --locked --color=always -- --color=always 2>&1 \
  | tee >(sed -E 's/\x1b\[[0-9;]*[mK]//g' > test.log)

他のツールでも考え方は同じで,色を強制するオプションが異なるだけです.

ツール 色を強制する指定
cargo --color=always
pytest --color=yes
git -c color.ui=always
grep / ls --color=always

root 権限が必要なファイルに書き込む

sudo echo ... > /etc/... は,リダイレクトを処理するのが sudo 前の自分のシェルなので権限エラーになります. 書き込みを tee に任せ,tee を sudo で実行します.

echo "127.0.0.1 mlflow.local" | sudo tee -a /etc/hosts > /dev/null

末尾の > /dev/null は画面へのエコーを捨てるためのものです.-a を忘れるとファイルが上書きされる点に注意してください.

データ分析での使いどころ

例 4 (学習・バッチ処理のログを残す) 長時間かかる学習やバッチ処理では,進捗を画面で追いながらログを残します.

python -u train.py --config config.yml 2>&1 | tee "logs/train_$(date +%Y%m%d_%H%M%S).log"

Python は出力先が TTY でないと stdout をブロックバッファリングするため,そのままでは画面への表示がまとまって遅れて出ます. -u(または環境変数 PYTHONUNBUFFERED=1)でバッファリングを無効にします.

Python 以外のコマンドでは stdbuf が使えます.

stdbuf -oL ./long_job 2>&1 | tee job.log

例 5 (同じログに追記していく) ハイパーパラメータを変えながら繰り返し実行する場合は,-a で1つのファイルに追記します.

for lr in 0.1 0.01 0.001; do
  echo "=== lr=${lr} ===" | tee -a sweep.log
  python -u train.py --lr "${lr}" 2>&1 | tee -a sweep.log
done

例 6 (パイプラインの中間結果を保存する) 前処理をパイプでつないでいるとき,途中段階のデータをファイルに落としておくと,後から件数や中身を検証できます.

zcat access.log.gz \
  | grep -v "healthcheck" \
  | tee filtered.log \
  | awk '{print $1}' | sort | uniq -c | sort -rn | head

References