重要なお知らせ

「教えて! goo」は2025年9月17日(水)をもちまして、サービスを終了いたします。詳細はこちら>

電子書籍の厳選無料作品が豊富!

以下の二つの処理に違いを知りたいです。

% cat filename | COMMAND

% COMMAND < filename

どちらも、COMMANDにfilenameの中身を標準入力で与えています。

前者はファイル終端(EOF)がCOMMANDに送られず、後者はEOFも送られる、という認識でよいでしょうか?

A 回答 (6件)

No.2 & 4 です。



---
(1)におけるstraceの実行結果を載せると
% strace cat filename | COMMAND
....
---

これだと cat を strace することになってしまいます。

% cat filename | strace COMMAND

としないといけません。

その時注目すべきは read(0,...) というようにファイル記述子の0番に対する操作です。

この回答への補足

まず、(1)と(2)でscriptを用いて出力をファイルにダンプし、それらをdiffしたところ、かなりの量の違いが出力されました。プロセスIDなど、変わってしかるべき以外の細かい点もあります。これは、詳しく見ないと分からないですね。

次に、お勧めのように
% grep "read(0," ダンプ結果
として、(1)と(2)それぞれでread(0,...を抜き出し、diffを取ったところ、全く差がありませんでした。従って、read(0,...という標準入力の読み取りに関する操作では、違いがないということが判明しました。

さらに、ダンプ結果において、(1)の方法ではエラーが出ている箇所を探し出してその周辺を比較しました。制限字数が足りないので次に出します。

補足日時:2006/12/06 13:37
    • good
    • 0
この回答へのお礼

どうもすみません!
ありがとうございます。

お礼日時:2006/12/06 13:27

>全く一緒ということでしょうか?違いは全くありませんか?



ファイルの先頭から末尾まで順に読む処理であれば大きな違いはありません。違うのはread()で一度に読むデータ量です。Cで言うとgetchar()やfgets()で読む限り違いは無いです。厳密には(1)はcatが読んで書く速さより速くCOMMANDが入力を読むならば違いが出ます(待ちが発生する)。

ファイルの先頭から末尾まで順に読む以外の処理、例えば一度最後まで読んだあと再度先頭から読み直すとかの処理をしているのならば、(2)は可能ですが、(1)では不可能です。

また、入力がファイルかパイプかを調べてそれにより異なる処理をしているのなら当然違いが出ます。
    • good
    • 0
この回答へのお礼

ありがとうございます。
seek動作のほかにも、時間も変わりえるんですね。

No.4のお勧めどおり、まずはこのソフトウエアがパイプのときにどうなるか、確認して見ます。

お礼日時:2006/12/06 09:44

再度 No.2 です。



ひょっとしてこの市販ソフトは、入力に pipe を許していないのではないでしょうか?

もし COMMAND が標準入力がファイルであることを前提に、lseek() していたりすると、pipe に対する lseek() は許されていませんので、当然エラーになります。この場合、「EOF がどうのこうの」というエラーメッセージになることも十分考えられます(lseek() の errno をちゃんと見ていなかった場合)。

これを確かめるには strace をすればいいんですが。どうしても原因を知りたいのであれば、man strace を見てください。

この回答への補足

(1)におけるstraceの実行結果を載せると

% strace cat filename | COMMAND
....
read(3, "400 148.7900 148.9000\n 0.09077 -"..., 4096) = 4096
write(1, "400 148.7900 148.9000\n 0.09077 -"..., 4096) = 4096
read(3, "+0014 35.460 -47.5400 -47.1900 "..., 4096) = 3102
write(1, "+0014 35.460 -47.5400 -47.1900 "..., 3102) = 3102
read(3, "", 4096) = 0
brk(0) = 0x806e000
brk(0) = 0x806e000
brk(0x806d000) = 0x806d000
brk(0) = 0x806d000
close(3) = 0
close(1) = 0
exit_group(0) = ?

でした。exit_group(0)=?ってのがおかしいのかと思ったのですが、(2)における実行結果も、最後は同様にexit_group(0)=?で終わっています。これが原因ではないようですね。もう少し調べて見ます。

補足日時:2006/12/06 12:22
    • good
    • 0
この回答へのお礼

ありがとうございます。straceを調べて見ます。

お礼日時:2006/12/06 09:41

>例えば、ktermなどの端末上でcat自身にEOFを知らせるにはCTR-Dをしますが、それはcatがCTR-Dというシグナル(実体)を受け取って判断しているわけではないということですか。



はい。違います。Ctrl-Dを認識するのはttyドライバです。ttyドライバは行頭でctrl-Dを入れると長さゼロのデータをプログラムに送ります。
この長さゼロのデータをプログラムはEOFと判断します。

ファイルから入力の場合は、ある長さのデータを読むわけですが、データがなくなって、さらにもう一度読むと、「長さがゼロのデータ」が読まれます。この長さゼロのデータをプログラムはEOFと判断します。端末の場合とプログラムの動きは同じです。

>COMMAND内にてファイル終端を判断させているのですが

具体的にどうやって終端を判断させているのですか?そこに間違いがあるのではないでしょうか?

この回答への補足

ありがとうございます。そうすると、

(1) % cat filename | COMMAND

(2) % COMMAND < filename

は全く一緒ということでしょうか?違いは全くありませんか?

このCOMMANDは、ある既成のソフトウエアなのですが、標準入力からのEOFを判断するようになっています。(1)では標準入力からのEOFを認識できずに読み込みエラーとなり、(2)ではEOFをちゃんと認識しています。

(1)と(2)で全く差がないのであれば、このCOMANNDが(1)と(2)とで動作が異なるような処理をしていることになるのでしょうね。もはやベンダーに尋ねるしかないかもしれないですね。

補足日時:2006/12/05 23:25
    • good
    • 0

fgetc() など FILE 操作の関数は EOF を返すので、EOF という実体があるような気がしても不思議ではないです。

が、実際には EOF という実体はなく、状態があるだけです。pipe の場合は、送る方の端を close() すると受け取り側で EOF になりますし、ファイルの場合はファイルの最後まで読めば(あるいはシークポインタがファイルの最後を指していれば)EOF になります。

cat はファイルを読み込んでは標準出力に出力し、EOF になったら終了します。この時出力がパイプで他のプログラムにつながっていた場合は、パイプの端が close() され、それが次のプログラムに伝わることになります。

ということでシェルのパイプでつなごうが、リダイレクトしようが EOF に関しては同じ結果になるハズです。

ただし、

% COMMAND | HOGEHOE

とやって、HOGEHOGE が EOF の前に終了してしまった、つまり pipe の入力端が close() されてしまった状態で、なおかつ出力しようとした場合、COMMAND には SIGPIPE シグナルが発生し、異常終了となります。これは man ページを見ていて途中で終了したりすると Broken pipe というメッセージがでるのと同じ現象です。

この回答への補足

ありがとうございます。
例えば、ktermなどの端末上でcat自身にEOFを知らせるにはCTR-Dをしますが、それはcatがCTR-Dというシグナル(実体)を受け取って判断しているわけではないということですか。

catはEOFを受け取ると終了、という説明を見かけた為、ファイルのEOFを受け取ると、EOFは出力せずに終了するのかと解釈していました。

ただ、現にパイプとリダイレクトで結果が異なるので、そうするとこのコマンドの内部処理の問題ということなのでしょうか・・・・

catやawkでパイプの端をclose()するような出力は、できない(存在しない)ということでしょうか。

補足日時:2006/12/05 20:14
    • good
    • 0

EOFの扱いに違いは無いと思います。



>% cat filename | COMMAND ...(1)
catの標準出力が、COMMANDの標準入力に接続される。
>% COMMAND < filename ...(2)
COMMANDの標準入力にfilenameの内容が送られる。

違いといえば、(2)と比べて、(1)は「cat」コマンドが余計に
起動するのでその分余計なリソースを使うという点でしょうか?

この回答への補足

ありがとうございます。

COMMAND内にてファイル終端を判断させているのですが、(1)ではファイル終端を見つけられずにエラーとなり、(2)ではファイル終端を見つけて正常終了となります。そのため、このような違いがあるのかと思いました。

確か、catはファイル終端を見つけるまで標準出力させるはずですが、そのためにファイル終端自身を標準出力していないのではないかと疑念を持ったわけです。

補足日時:2006/12/05 14:28
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!