リダイレクト

先日 リダイレクトとパイプについてちょろっと書いた。そのとき気になった部分を調べた。
気になったことは、リダイレクトを使った場合と、パイプを使った場合でプログラム内部で処理の違いが出てくるのか?ということ。とくに、ファイル位置の操作に関して。

準備

テストコード (a.c)
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char **argv)
{
  char    buf[1024];
  ssize_t rsize;

  do {
      memset(buf, 0, sizeof(buf));
      rsize  = read(0, buf, sizeof(buf));
      printf("read: [%s]\n", buf);
      // 読み込んだ分だけファイル位置を戻す→無限ループ
      if (lseek(0, (off_t)(-1 * rsize), SEEK_CUR) == -1) {
        printf("Error: %s\n", errno == ESPIPE ? "ESPIPE" : "Other");
      }
  } while (rsize > 0);

  return 0;
}
入力ファイル (input.txt)
aiueo

実行

リダイレクトの場合
% ./a.out < input.txt
read: [aiueo
]
read: [aiueo
]
.
.
. 繰り返し
パイプの場合
% cat input.txt | ./a.out
read: [aiueo
]
Error: ESPIPE
read: []
Error: ESPIPE

まとめ

リダイレクトは、lseek でファイル位置を操作できた。
パイプは lseek でファイル位置を操作しようとするとエラーが発生した。
http://www.linux.or.jp/JM/html/LDP_man-pages/man2/lseek.2.html によると

Linux では、 tty デバイスに lseek() を使用すると ESPIPE を返す。

とのこと。そりゃそうだよね。パイプとかソケットで通信していて、過去に受信したデータを読もうとするなんて。

まあ、こうなるのではという予想を確かめるための調査だったので、驚くようなことはなかった。

ところで、これを書くまでリダイレクトって用語の理解を間違えていたみたい。今まで、リダイレクトっていうと「>」「>>」「<」を思い浮かべていたけど、パイプももリダイレクトだね。でもやっぱり、リダイレクトっていったら先に挙げた3つかな。
パイプ ⊂ リダイレクト って感じ?
そういえば、ヒアドキュメントってのもあったな、全然使わないから忘れてた...