Linux/Macなどのターミナル上での作業を想定しています。
「出力を表示しつつもファイルに書き出す」操作は、teeへパイプを結ぶことで実現できます。得られた出力を目視しつつ、ログファイルとして保存する時などに重宝します。
$ echo "hoge" | tee hoge.log
hoge
$ cat hoge.log # => hoge
書き出すファイルをローテートさせる
teeはとてもシンプルで便利なコマンドなのですが、要求が複雑になると対応が難しくなります。
- 上の例でいう
hoge.log
が巨大になってしまう - いつ頃に出力されたのか日付入りのファイルに出力させたい
こんな時には、teeでは力不足になってしまいます。
そこで、ログローテートをしてくれるコマンドにパイプするようにします。例えば、rotatelogsやcronologがあります。
ここではrotatelogs1を使ってみました。-n
オプション2と出力先ファイル、1つあたりのファイルサイズを指定すると、ファイルにsuffixを付けた上でローテートしてくれます。
# 3194880 = 3M (3 * 1024 * 1024)
$ yes hoge | head -c 3194880 | rotatelogs -n 3 /tmp/hoge.log 1M
$ wc -c /tmp/hoge*
1064960 /tmp/hoge.log
1064960 /tmp/hoge.log.1
1064960 /tmp/hoge.log.2
3194880 total
表示もさせたい
ファイル出力についてはいい感じになったのですが、rotatelogsは標準入力を吸い取ってしまうので、そのまま使うとteeのように表示と保存を両立させることができません。
解決法として単純なのは、rotatelogsには-e
オプションがあるのでそれを使うことです。標準入力をそのまま標準出力に流してくれます。
$ echo "hoge" | rotatelogs -e -n 3 hoge.log 1M
hoge
別のアプローチとして、process substitutionを使う方法が考えられそうです。
$ echo "hoge" | tee >(rotatelogs -n 3 hoge.log 1M)
hoge
$ cat hoge.log
hoge
つまり、teeでターミナルに出力させつつ、ファイルの書き出し先を名前付きパイプにした上で、そちらにrotatelogsの標準入力をつなぎます。前述のcronologには-e
のようなオプションがなさそうですし、こちらのほうがより汎用性が高そうに見えます。
まとめ
- 標準出力を保存するときはteeが使える
- 保存先にローテートなどの工夫をしたい時はrotatelogsなどを導入するとよさそう
- process substitutionは色々と応用が利きそう