tee -
パイプの中身を複製する
#define _GNU_SOURCE /* feature_test_macros(7) 参照 */
#include <fcntl.h>
ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags);
tee()
は、ファイルディスクリプター
fd_in
が参照するパイプからファイルディスクリプター
fd_out
が参照するパイプへ最大
len
バイトのデータを複製する。
この操作では、複製されるデータは
fd_in
からは消費されない。したがって、これらのデータをこの後の
splice(2)
でコピーすることができる。
flags is a bit mask that is composed by ORing together zero or more of
the following values:
- SPLICE_F_MOVE
- 現在のところ
tee()
では何の効果もない。
splice(2) 参照。
- SPLICE_F_NONBLOCK
- 入出力で停止 (block)
しない。詳細は splice(2)
参照。
- SPLICE_F_MORE
- 現在のところ
tee()
では何の効果もないが、将来的には実装される可能性がある。
splice(2) 参照。
- SPLICE_F_GIFT
-
tee()
では未使用。 vmsplice(2)
参照。
成功して完了すると、
tee()
は入出力間で複製されたバイト数を返す。
返り値 0
はデータの転送が行われなかったことを示す。
この場合、処理を停止
(block)
しても無意味である。
なぜなら、
fd_in
が参照するパイプの書き込み側に接続されている者がいないからである。
エラーの場合、
tee() は
-1 を返し、
errno
にエラーを示す値を設定する。
- EAGAIN
-
SPLICE_F_NONBLOCK was specified in flags or
one of the file descriptors had been marked as nonblocking (
O_NONBLOCK) , and the operation would block.
- EINVAL
-
fd_in と fd_out
のどちらかがパイプを参照していない。もしくは
fd_in と fd_out
が同じパイプを参照している。
- ENOMEM
- メモリー不足。
tee() システムコールは
Linux 2.6.17
で初めて登場した。
ライブラリによるサポートは
glibc バージョン 2.5
で追加された。
このシステムコールは
Linux 固有である。
概念としては、
tee()
は二つのパイプ間でデータのコピーを行う。
しかし、実際には実データのコピーは行われない。
内部では、
tee()
は入力側に対する参照だけを作成することで出力側にデータを
追加する。
以下の例は、
tee()
システムコールを使って、
基本的な
tee(1)
プログラムを実装したものである。
以下は利用例である。
$ date |./a.out out.log | cat
Tue Oct 28 10:06:00 CET 2014
$ cat out.log
Tue Oct 28 10:06:00 CET 2014
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
int
main(int argc, char *argv[])
{
int fd;
int len, slen;
if (argc != 2) {
fprintf(stderr, "Usage: %s <file>\n", argv[0]);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
do {
/*
* tee stdin to stdout.
*/
len = tee(STDIN_FILENO, STDOUT_FILENO,
INT_MAX, SPLICE_F_NONBLOCK);
if (len < 0) {
if (errno == EAGAIN)
continue;
perror("tee");
exit(EXIT_FAILURE);
} else
if (len == 0)
break;
/*
* Consume stdin by splicing it to a file.
*/
while (len > 0) {
slen = splice(STDIN_FILENO, NULL, fd, NULL,
len, SPLICE_F_MOVE);
if (slen < 0) {
perror("splice");
break;
}
len -= slen;
}
} while (1);
close(fd);
exit(EXIT_SUCCESS);
}
splice(2),
vmsplice(2),
pipe(7)
この man ページは Linux
man-pages
プロジェクトのリリース
5.10
の一部である。プロジェクトの説明とバグ報告に関する情報は
https://www.kernel.org/doc/man-pages/
に書かれている。