• 締切済み

パイプラインとリダイレクトの違い

以下の二つの処理に違いを知りたいです。 % cat filename | COMMAND % COMMAND < filename どちらも、COMMANDにfilenameの中身を標準入力で与えています。 前者はファイル終端(EOF)がCOMMANDに送られず、後者はEOFも送られる、という認識でよいでしょうか?

みんなの回答

  • chirubou
  • ベストアンサー率37% (189/502)
回答No.6

No.2 & 4 です。 --- (1)におけるstraceの実行結果を載せると % strace cat filename | COMMAND .... --- これだと cat を strace することになってしまいます。 % cat filename | strace COMMAND としないといけません。 その時注目すべきは read(0,...) というようにファイル記述子の0番に対する操作です。

amu
質問者

お礼

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

amu
質問者

補足

まず、(1)と(2)でscriptを用いて出力をファイルにダンプし、それらをdiffしたところ、かなりの量の違いが出力されました。プロセスIDなど、変わってしかるべき以外の細かい点もあります。これは、詳しく見ないと分からないですね。 次に、お勧めのように % grep "read(0," ダンプ結果 として、(1)と(2)それぞれでread(0,...を抜き出し、diffを取ったところ、全く差がありませんでした。従って、read(0,...という標準入力の読み取りに関する操作では、違いがないということが判明しました。 さらに、ダンプ結果において、(1)の方法ではエラーが出ている箇所を探し出してその周辺を比較しました。制限字数が足りないので次に出します。

全文を見る
すると、全ての回答が全文表示されます。
  • notnot
  • ベストアンサー率47% (4856/10271)
回答No.5

>全く一緒ということでしょうか?違いは全くありませんか? ファイルの先頭から末尾まで順に読む処理であれば大きな違いはありません。違うのはread()で一度に読むデータ量です。Cで言うとgetchar()やfgets()で読む限り違いは無いです。厳密には(1)はcatが読んで書く速さより速くCOMMANDが入力を読むならば違いが出ます(待ちが発生する)。 ファイルの先頭から末尾まで順に読む以外の処理、例えば一度最後まで読んだあと再度先頭から読み直すとかの処理をしているのならば、(2)は可能ですが、(1)では不可能です。 また、入力がファイルかパイプかを調べてそれにより異なる処理をしているのなら当然違いが出ます。

amu
質問者

お礼

ありがとうございます。 seek動作のほかにも、時間も変わりえるんですね。 No.4のお勧めどおり、まずはこのソフトウエアがパイプのときにどうなるか、確認して見ます。

全文を見る
すると、全ての回答が全文表示されます。
  • chirubou
  • ベストアンサー率37% (189/502)
回答No.4

再度 No.2 です。 ひょっとしてこの市販ソフトは、入力に pipe を許していないのではないでしょうか? もし COMMAND が標準入力がファイルであることを前提に、lseek() していたりすると、pipe に対する lseek() は許されていませんので、当然エラーになります。この場合、「EOF がどうのこうの」というエラーメッセージになることも十分考えられます(lseek() の errno をちゃんと見ていなかった場合)。 これを確かめるには strace をすればいいんですが。どうしても原因を知りたいのであれば、man strace を見てください。

amu
質問者

お礼

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

amu
質問者

補足

(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)=?で終わっています。これが原因ではないようですね。もう少し調べて見ます。

全文を見る
すると、全ての回答が全文表示されます。
  • notnot
  • ベストアンサー率47% (4856/10271)
回答No.3

>例えば、ktermなどの端末上でcat自身にEOFを知らせるにはCTR-Dをしますが、それはcatがCTR-Dというシグナル(実体)を受け取って判断しているわけではないということですか。 はい。違います。Ctrl-Dを認識するのはttyドライバです。ttyドライバは行頭でctrl-Dを入れると長さゼロのデータをプログラムに送ります。 この長さゼロのデータをプログラムはEOFと判断します。 ファイルから入力の場合は、ある長さのデータを読むわけですが、データがなくなって、さらにもう一度読むと、「長さがゼロのデータ」が読まれます。この長さゼロのデータをプログラムはEOFと判断します。端末の場合とプログラムの動きは同じです。 >COMMAND内にてファイル終端を判断させているのですが 具体的にどうやって終端を判断させているのですか?そこに間違いがあるのではないでしょうか?

amu
質問者

補足

ありがとうございます。そうすると、 (1) % cat filename | COMMAND (2) % COMMAND < filename は全く一緒ということでしょうか?違いは全くありませんか? このCOMMANDは、ある既成のソフトウエアなのですが、標準入力からのEOFを判断するようになっています。(1)では標準入力からのEOFを認識できずに読み込みエラーとなり、(2)ではEOFをちゃんと認識しています。 (1)と(2)で全く差がないのであれば、このCOMANNDが(1)と(2)とで動作が異なるような処理をしていることになるのでしょうね。もはやベンダーに尋ねるしかないかもしれないですね。

全文を見る
すると、全ての回答が全文表示されます。
  • chirubou
  • ベストアンサー率37% (189/502)
回答No.2

fgetc() など FILE 操作の関数は EOF を返すので、EOF という実体があるような気がしても不思議ではないです。が、実際には EOF という実体はなく、状態があるだけです。pipe の場合は、送る方の端を close() すると受け取り側で EOF になりますし、ファイルの場合はファイルの最後まで読めば(あるいはシークポインタがファイルの最後を指していれば)EOF になります。 cat はファイルを読み込んでは標準出力に出力し、EOF になったら終了します。この時出力がパイプで他のプログラムにつながっていた場合は、パイプの端が close() され、それが次のプログラムに伝わることになります。 ということでシェルのパイプでつなごうが、リダイレクトしようが EOF に関しては同じ結果になるハズです。 ただし、 % COMMAND | HOGEHOE とやって、HOGEHOGE が EOF の前に終了してしまった、つまり pipe の入力端が close() されてしまった状態で、なおかつ出力しようとした場合、COMMAND には SIGPIPE シグナルが発生し、異常終了となります。これは man ページを見ていて途中で終了したりすると Broken pipe というメッセージがでるのと同じ現象です。

amu
質問者

補足

ありがとうございます。 例えば、ktermなどの端末上でcat自身にEOFを知らせるにはCTR-Dをしますが、それはcatがCTR-Dというシグナル(実体)を受け取って判断しているわけではないということですか。 catはEOFを受け取ると終了、という説明を見かけた為、ファイルのEOFを受け取ると、EOFは出力せずに終了するのかと解釈していました。 ただ、現にパイプとリダイレクトで結果が異なるので、そうするとこのコマンドの内部処理の問題ということなのでしょうか・・・・ catやawkでパイプの端をclose()するような出力は、できない(存在しない)ということでしょうか。

全文を見る
すると、全ての回答が全文表示されます。
回答No.1

EOFの扱いに違いは無いと思います。 >% cat filename | COMMAND ...(1) catの標準出力が、COMMANDの標準入力に接続される。 >% COMMAND < filename ...(2) COMMANDの標準入力にfilenameの内容が送られる。 違いといえば、(2)と比べて、(1)は「cat」コマンドが余計に 起動するのでその分余計なリソースを使うという点でしょうか?

amu
質問者

補足

ありがとうございます。 COMMAND内にてファイル終端を判断させているのですが、(1)ではファイル終端を見つけられずにエラーとなり、(2)ではファイル終端を見つけて正常終了となります。そのため、このような違いがあるのかと思いました。 確か、catはファイル終端を見つけるまで標準出力させるはずですが、そのためにファイル終端自身を標準出力していないのではないかと疑念を持ったわけです。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • シェルのリダイレクトとパイプについて

    シェルのリダイレクトとパイプについての質問です. リダイレクトでコマンドの標準出力をファイルに指定した後に, パイプを置いて,もう一つコマンドを並べたとき, 後の方のコマンドの標準入力はどうなるのでしょうか? 例えば, ls >outfile |cat ならば, catの標準入力には,何も入ってこないと思うのですが, これを実行すると,lsの結果がoutfileに書き込まれ, 次のプロンプトが表示されます. 普通,catを引数なしで実行すると, EOFが入力されるまで,入力待ちになると思うのですが, こうならないのは,シェルがcatの標準入力にEOFを入力したからだと 考えていいのでしょうか. よろしくお願いします. (質問の意味が分かりにくければご指摘下さい.)

  • cshスクリプト内での”ヒアドキュメント”とパイプライン

    cshスクリプト内での”ヒアドキュメント”とパイプライン cshスクリプト内で、 1)比較的大量の入力を必要とするコマンドcommand1 2)command1の出力をawkにかけて整形する ことをしたいのです。ここで、条件として、一時ファイルを作らないという制約があります。 ここで、ヒアドキュメントというのでしょうか? command1 <<EOF very very long text very very long text very very long text very very long text EOF を用い、command1の入力とします。 そして、command1の標準出力をawkにかけたいのです。 そこで #!/bin/csh ( command1<<EOF very very long text very very long text very very long text very very long text EOF)| awk '............' とかやってみましたが、うまくいきません。 command1 <<EOF | awk '....' very very long text very very long text very very long text EOF もだめです。 別に、<<EOFにこだわるつもりはないのですが、cshスクリプト内で、かつ一時ファイルの作成をせずに、 このようなことをやる方法はあるでしょうか? 入出ストリームの切り替えとかでできそうな木もするのですが、できればそれはなしでお願いします。 なんでcshわざわざこんなことをやるんだ、一時ファイル作ればいいじゃん、という意見ごもっともですが、cshの理解のため、あえてやってみたいのです。 よろしくお願いいたします。

  • SUNOSのエスケープシーケンス(終端文字¥0)について・・。

    こんにちわ, 今SUNOSでC言語を学んでいるのですが, 終端文字は\0だとおもっていたのですが,うまくいきません。具体的には次のとおりです。 char command[1000]; strcpy(command, "cat "); strcat(command, _i_filename); strcat(command, " |sed -e 's/ /\\x0/g' "); /* sのあとはスペース1つ */ system(command); Linuxではスペースの所に'\0'文字が入るのですが,SUNOSではそれをx0と認識してしまうようです。 なにかSEDのバージョンや会社に違いがあるからなのでしょうか。 よろしくお願いします。

  • kシェルのリダイレクトについて

    kシェルを用いてツールを作っています。 このツールを使用する際には、全ての出力をファイルに出力して 処理の最後に出力ファイルをcatで表示したいと考えております。 出力は、exec 2>&1 ~.logでファイル出力しますが、 そのファイルをcatすると、catの結果もファイル出力になってしまいます。 catを標準出力するにはどうしたら宜しいでしょうか?

  • 二つの違い

    「程度の差こそあれ、気分が落ち込む」 「気分が落ち込む」 この二つの違いは、前者が「10~1」までの間なのに対し、後者は「10~0」までの間、という認識で問題ないと思いますか?

  • 標準I/OからのEOFの入力

    iBook(OSX)のプロジェクトビルダーでcarbonのファイルを作っています。プログラムの中で  getchar() != EOF という文で入力がEOFかどうかを検出しようとしているのですがreturnやenterではEOFと認識されないようです。標準I/O (キーボード)からEOFを入力するにはどうしたら良いのでしょうか。

    • 締切済み
    • Mac
  • テキストの読込について

    あいうえお かきくけこ さしすせそ ↑のような中身のテキストファイルを読み込んで、 あいうえおかきくけこさしすせそ ↑のように、改行をなくして新規テキストに出力する プログラムを作成中なのですが、上手くいかず 困っています。 改行を無視した取り込みは出来るのでしょうか? もしくは、LineInput等で読み込んだ後、 改行を取り除くような処理をするのでしょうか? 下記は、現在まで作ったプログラムなのですが、 これだと、改行も同時に取り込んでしまっています。 Private Sub Command1_Click() Dim sData As String Dim FileName As String CommonDialog1.Filter = "テキスト|*.txt|全てのファイル|*.*" CommonDialog1.ShowOpen FileName = CommonDialog1.FileName Open FileName For Input As #1 Do Until EOF(1) Line Input #1, sData Loop Close #1 環境は、WindowsXP、VB6.0エンタープライズです。 以上、宜しくお願い致します<(_ _)>

  • C言語のファイル処理について

    環境 OS:Windows VISTA Ultimate コンパイラ:Borland C++ Compiler 5.5 Cの基礎的な勉強をしています。2つほど質問があります。 1つ目は、ファイル処理の勉強としてプログラムを作っているのですがファイルが上手く開けません。プログラムとしてはファイルを開いて、ファイル内に記述されている数値を取り出し、計算を行う簡単なものを作っています。ソースは以下のものになります。 #define N 256 int file_read(char filename[] , int count[]) { int m; FILE *fp; fp=fopen(filename,"r"); if(fp==NULL) { /* オープン失敗 */ printf("Not Found File\n"); return -1; /* 戻り値-1 */ } while((m = fgetc(fp)) != EOF) { 読み取った数値配列に格納する処理 } fclose(fp); return 0; } int operation(int count[]) { 計算処理 return 0; } int main(void) { int *count[N]; char *filename[256]; memset(count, 0, sizeof(count)); /* 変数・配列初期化 */ printf("Please Input Filename:"); fgets(filename, sizeof(filename), stdin ); if(file_read(filename,count) != -1) operation(count); return 0; }  バッファオーバーランの事を考え、fgetsによるキー入力にしたのですがファイルオープン失敗になってしまいます。fgetsのあと、変数filenameの中身を確認したところ、キー入力した文字はきちんと代入されていました。オープンするファイルはきちんとあるのですが・・。  fgetsをscanfに変えた場合は上手くいくので書式指定をしてscanfを使えばいいのでしょうが、なぜfgetsで上手くいかないでしょうか? 2つ目はgetchar()とfgets()に関してです。 while((c = getchar()) != EOF) { . .処理 . fgets(変数, sizeof(変数), stdin ); . .処理 . } とした場合、fgetsの処理が無視されてしまいます。 これはどういったことが原因なのでしょうか。 ご教授、お願いいたします。

  • 2つの医療用クロックスの違いは何?

    医療用クロックスが以下の2つ発売されていますが、 HPなどを見てもまったく違いが分かりません ・crocswatt vent ・specialist vent 前者のほうが新しいモデルで、ドラマに登場したため人気商品となっているようですが、 見た目を含め後者と何が違うのかさっぱりわからず、 それなら少し安い後者のほうを買ったほうがいいのだろうかと迷っています。 違いが分かる方、教えてください。

  • Windowsの検索とGoogleDesktopSearchの違い

    Windows標準で使用できる検索(スタート⇒検索)と GoogleDesktopSearchなどのローカルディスク検索ソフトの違いって何なのでしょうか? 検索速度の違いだけは分かったのですが、 両者とも   ファイルの中身も検索可能   ネットワーク越しのファイルも検索可能 と認識しております。 検索速度だけの違いでしょうか? どなたかご存知でしたら教えてください。 よろしくお願い致します。