[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

17.1 tee: 出力を複数のファイルやプロセスにリダイレクトする

tee コマンドは、標準入力を標準出力にコピーするとともに、 引数として指定されたファイル (複数可) にもコピーする。 これは、あるデータをパイプに送るだけでなく、同時にそのコピーを保存したい場合に、便利である。

書式:

 
tee [option]… [file]…

書き出し先のファイルがまだ存在していなければ、作成する。 書き出し先のファイルがすでに存在している場合は、‘-a’ オプションを使用しないかぎり、ファイルに前からあったデータは上書きされる。

GNU coreutils の従来のバージョンでは (v5.3.0 - v8.23)、 file として ‘-’ を指定すると、tee は入力のコピーをもう一つ標準出力に書き出していた。 しかし、二重になった出力は、あまり役に立つものではなかったので、 現在では POSIX の規格に従い、そこではっきりと規定されているように、 ‘-’ をそういう名前のファイルとして取り扱うようになっている。

このプログラムでは以下のオプションが使用できる。参照: 共通オプション.

-a
--append

指定されたファイルの末尾に標準入力を追加する。すなわち、ファイルを上書きしない。

-i
--ignore-interrupts

割り込みシグナルを無視する。

-p
--output-error[=mode]

出力にエラーがあったときの動作を調整する。 長い形式のオプションを使えば、下記の mode から動作を選択することができる。

warn

パイプを含めて、出力のオープンや書き出しでエラーが起きると、警告メッセージを出す。 エラー発生後もまだオープンされているファイルやパイプがあれば、それに対する書き込みは続行される。 出力のいづれかにエラーがあれば、終了ステータスは失敗を示す。

warn-nopipe

これが、mode が指定されないときや、短い形式の ‘-p’ が使用されたときのデフォルトの mode である。 パイプ以外について、出力のオープンや書き出しでエラーが起きると、警告メッセージを出す。 エラー発生後もまだオープンされているファイルやパイプがあれば、それに対する書き込みは続行される。 パイプ以外の出力にエラーがあれば、終了ステータスは失敗を示す。

exit

パイプを含めて、出力のオープンや書き出しでエラーが起きると、終了する。

exit-nopipe

パイプ以外について、出力のオープンや書き出しでエラーが起きると、終了する。

大量のデータの転送を行いながら、同時にそのデータのサマライズも行いたい、 改めてデータを読み直すようなことはしたくない。tee は、そういうときに便利である。 たとえば、DVD イメージをダウンロードしているとき、 その場ですぐ、署名やチェックサムを確認したくなることがよくある。 単に次のようにするのは、効率が悪い。

 
wget http://example.com/some.iso && sha1sum some.iso

上記コマンドの問題点の一つは、ただでさえ時間のかかる SHA1 の計算に取りかかる前に、 ダウンロードが完了するのを待たなければならないことだ。 たぶん、さらに問題なのは、上記のやり方では、 DVD イメージを改めて読み直さなければならないことだろう (一度目の読み込みは、ネットワークから)。

こうした作業を行う効率的な方法は、ダウンロードと SHA1 の計算を同時に、 交互に実行することである。そうすれば、プロセス全体が平行してスムーズに進むので、 無駄な時間を使わずに、チェックサムが手に入る。

 
# ちょっと凝った方法。プロセス置換の実例をご覧に入れるため。
wget -O - http://example.com/dvd.iso \
  | tee >(sha1sum > dvd.sha1) > dvd.iso

こうすれば、tee は、出力を目当てのファイルに書き出すだけでなく、パイプにも書き出す。 そして、後者では、sha1sum を実行し、最終的なチェックサムを ‘dvd.sha1’ という名前のファイルに保存することになる。

しかし、気をつけていただきたい。上記の例は、プロセス置換 (process substitution) と呼ばれる最近のシェルの機能を当てにしている (上記の‘>(command)’ という構文のことである。See (bash)Process Substitution section ‘Process Substitution’ in The Bash Reference Manual.)。 そのため、zsh, bash, ksh ではうまく動作するが、/bin/sh では動作しない。 従って、こうしたコードをシェルスクリプトで使用するときは、スクリプトの先頭に ‘#!/bin/bash’ などと書くことを忘れてはいけない。

次のことにも気をつけていただきたい。プロセス置換のいづれかが (あるいは、パイプに渡された標準出力が)、 データをすべて処理し尽くす前に終了してしまうことがあるかもしれない。 そうした場合に、tee が入力の処理を続行して、 それを残っている出力先に渡すことができるようにするには、 ‘-p’ オプションが必要になる。

上記の例は、書き出しを 1 個のファイルと 1 個のプロセスに行っているだけだ。 その程度なら、もっと普通の、もっと移植性のある使い方をした方がずっとよい。

 
wget -O - http://example.com/dvd.iso \
  | tee dvd.iso | sha1sum > dvd.sha1

tee が二つのプロセスに書き込むように、この例を拡張して、MD5 と SHA1 のチェックサムを平行して計算させることもできる。 その場合は、プロセス置換が必要になる。

 
wget -O - http://example.com/dvd.iso \
  | tee >(sha1sum > dvd.sha1) \
        >(md5sum > dvd.md5) \
  > dvd.iso

このテクニックは、パイプから入ってくるデータの圧縮したコピーを作りたいときにも、役に立つ。 ‘du -ak’ の出力するディスク使用量のデータを要約して、 グラフィカルに表示するツールを考えていただきたい。 ディレクトリ階層が膨大だと、‘du -ak’ は実行に長い時間がかかるだろうし、 いともたやすくテラバイトのデータを作成してくれるだろう。 そこで、‘du’ コマンドをむやみに再実行することはやりたくない。 また、圧縮されていない出力を保存しておきたくもない。

これを効率の悪い方法でやると、du の出力全部の圧縮を済ませるまで、 GUI ツールを起動することすらできない。

 
du -ak | gzip -9 > /tmp/du.gz
gzip -dc /tmp/du.gz | xdiskusage -a

tee とプロセス置換を使えば、GUI ツールを直ちに起動できるし、 圧縮ファイルの展開も全くやらないですむ。

 
du -ak | tee >(gzip -9 > /tmp/du.gz) | xdiskusage -a

最後にもう一つ。常に 2 種類以上の圧縮した tar アーカイブ (tarball) を一度に作ることにしている場合は、より効率のよいやり方ができるかもしれない。 たとえば、make distgzipbzip2 の両方で圧縮した tar アーカイブを作成するような場合だ。automake が生成する ‘Makefile’ のルールは、たいてい、こんなふうにコマンドを連続して実行することで、 圧縮した tar アーカイブを二つ作成している (少し単純化してある)。

 
tardir=your-pkg-M.N
tar chof - "$tardir" | gzip  -9 -c > your-pkg-M.N.tar.gz
tar chof - "$tardir" | bzip2 -9 -c > your-pkg-M.N.tar.bz2

しかしながら、アーカイブの作成・圧縮の対象になっているディレクトリ階層が、 数メガバイトより大きい場合は — 使用しているシステムがマルチプロセッサを搭載し、 メモリがふんだんにある場合はなおさらそうだが — ディレクトリの中身を 1 回だけ読み込み、 圧縮プログラムを平行して走らせることで、ずっと効率のよい仕事ができる。

 
tardir=your-pkg-M.N
tar chof - "$tardir" \
  | tee >(gzip -9 -c > your-pkg-M.N.tar.gz) \
  | bzip2 -9 -c > your-pkg-M.N.tar.bz2

プロセス置換が表示する出力をさらに処理したいとしよう。 もし、そうしたプロセスがアトミックな書き出しをしているならば (すなわち、一度の書き出しが、システムの PIPE_BUF サイズよりも小さければ)、 そういうことも次のような構文で可能である。

 
tardir=your-pkg-M.N
tar chof - "$tardir" \
  | tee >(md5sum --tag) > >(sha256sum --tag) \
  | sort | gpg --clearsign > your-pkg-M.N.tar.sig

終了ステータス 0 は成功を示し、0 以外の値は失敗を示す。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

This document was generated on June 7, 2022 using texi2html 1.82.