質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

標準入力

標準入力(stdin)は、プログラムが標準的に用いるデータ入力元。リダイレクトしない限り、プログラムを起動した端末のキーボードが標準入力になります。UNIX系OSやC言語に実装されて普及した概念ですが、他のOSや言語も含めた総称としても使われます。

標準出力

標準出力(stdout)は、プログラムが標準的に用いるデータ出力元。標準出力に書き込み要求を発行しすることにより、ディスプレイ装置にデータを表示することができます。UNIX系OSやC言語に実装されて普及した概念ですが、他のOSや言語も含めた総称としても使われます。

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

UNIX

UNIXとは、AT&Tのベル研究所で開発されたコンピューター用のマルチユーザー・マルチタスクのオペレーションシステム(OS)です。政府や教育機関や研究所で広範囲に採用されています。

Q&A

解決済

2回答

2853閲覧

C言語UNIX パイプによるシステムの作成について

tukareta

総合スコア6

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

標準入力

標準入力(stdin)は、プログラムが標準的に用いるデータ入力元。リダイレクトしない限り、プログラムを起動した端末のキーボードが標準入力になります。UNIX系OSやC言語に実装されて普及した概念ですが、他のOSや言語も含めた総称としても使われます。

標準出力

標準出力(stdout)は、プログラムが標準的に用いるデータ出力元。標準出力に書き込み要求を発行しすることにより、ディスプレイ装置にデータを表示することができます。UNIX系OSやC言語に実装されて普及した概念ですが、他のOSや言語も含めた総称としても使われます。

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

UNIX

UNIXとは、AT&Tのベル研究所で開発されたコンピューター用のマルチユーザー・マルチタスクのオペレーションシステム(OS)です。政府や教育機関や研究所で広範囲に採用されています。

0グッド

2クリップ

投稿2020/07/13 05:11

編集2020/07/13 05:17

UNIXシステムコールに関する質問です.
パイプシステムを用いて,与えられたコマンドを実行し,コマンドの標準入力に与えられたデータを指定したファイルにコピーするプログラムを作成したいのですがどうもうまく作動しません.
指摘アドバイス,回答お願いします.

例えば[./a.out file ls]とすればlsを実行し,その標準出力の内容がfileに保存されます.

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <unistd.h> 4#include <fcntl.h> 5 6#define BSIZE 512 7main(int argc, char **argv) 8{ 9 int pid, p_fd[2], fd; 10 char *new_program, **new_argv; 11 char buf[BSIZE]; 12 13 if (argc < 2) { 14 fprintf(stderr,"usage: %s command arg...\n",argv[0]); 15 exit(1); 16 } 17 18 pipe(p_fd); 19 20 if ((pid = fork()) == 0) { 21 /* child process */ 22 close(p_fd[0]); 23 close(1); 24 dup(p_fd[1]); 25 close(p_fd[1]); 26 27 new_program = argv[2]; 28 new_argv = &argv[2]; 29 execvp(new_program,new_argv); 30 perror(new_program); 31 32 exit(1); 33 } 34 35 /* parent process */ 36 if (pid == -1) { 37 perror("fork"); 38 exit(1); 39 } 40 41 close(p_fd[1]); 42 close(0); 43 dup(p_fd[0]); 44 close(p_fd[0]); 45 46 fd = open(argv[1],O_WRONLY|O_CREAT|O_TRUNC,0644); 47 while (read(p_fd[0],buf,BSIZE) != 0) { 48 write(fd,buf,BSIZE); 49 } 50 close(fd); 51 52 exit(1); 53}

子プロセスでコマンドの実行,親プロセスで標準入力をファイルに書くという考え方をしています.

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hidezzz

2020/07/13 05:18

「どうもうまく作動しません.」とは提示ソースではどういう状態になるのでしょうか?またソースのどのへんが意図通りになっていないかはある程度絞り込めていますか?
tukareta

2020/07/13 05:27

実行したらコマンドも実行されずに終了もしない状態です. 子プロセスは間違えてないと思うので,親プロセスのファイルの読み書き,あるいはパイプの繋ぎに問題があると思っています.
guest

回答2

0

ベストアンサー

間違いは、
・メインでreadするFDがおかしい。クローズしたFDから読んでいる。
readの返り値を理解していない。というかreadwriteの使い方が分かっていない。
の2点です。

あと、関数の返値をチェックしていないのが各所にあるのが改善ポイントです。
readの返り値が-1であるかチェックしていれば1つめの誤りには気づけたはず。

diff

1--- bb.c 2020-07-13 14:30:39.473613426 +0900 2+++ aa.c 2020-07-13 14:29:48.886623825 +0900 3@@ -9,6 +9,7 @@ 4 int pid, p_fd[2], fd; 5 char *new_program, **new_argv; 6 char buf[BSIZE]; 7+ int x; 8 9 if (argc < 2) { 10 fprintf(stderr,"usage: %s command arg...\n",argv[0]); 11@@ -44,8 +45,9 @@ 12 close(p_fd[0]); 13 14 fd = open(argv[1],O_WRONLY|O_CREAT|O_TRUNC,0644); 15- while (read(p_fd[0],buf,BSIZE) != 0) { 16- write(fd,buf,BSIZE); 17+ while ((x=read(0,buf,BSIZE)) != 0) { 18+ if(x<0) { perror("read"); exit(1); } 19+ write(fd,buf,x); 20 } 21 close(fd); 22

投稿2020/07/13 05:46

編集2020/07/13 09:23
otn

総合スコア84423

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

otn

2020/07/13 05:50

+ while ((x=read(0,buf,BSIZE)) >0) { + write(fd,buf,x); } + if(x<0) { perror("read"); exit(1); } のほうが良かったか。
tukareta

2020/07/13 06:04

回答ありがとうございます.書き換えたところ動作しました. write readシステムコールの引数と返り値についてもう一度勉強しなおしたいと思います.
guest

0

otnさんの回答とほぼ一緒ですが別解です。
違いは、親プロセス側においてpipe()で作った入力パイプを標準入力へつなげかえることをぜずに直接読むようにしているところです。
親プロセスが何回もfork()+exec()して子プロセスを作るようなケースを考えると、そのたびに親プロセスが入力パイプをいちいち標準入力につなげ変えるようにすることは少ないような気がします。
(子プロセスの生存期間がオーバーラップするような場合に親プロセスがどちらの標準入力を受けるのかを考える必要が出てきます。)

今回のように1回しか子プロセスを作らないのであればどちらでも良いのですが…。

diff

1--- hoge_org.c 2020-07-13 16:35:59.755122914 +0900 2+++ hoge.c 2020-07-13 16:37:34.179617510 +0900 3@@ -4,11 +4,12 @@ 4 #include <fcntl.h> 5 6 #define BSIZE 512 7-main(int argc, char **argv) 8+int main(int argc, char **argv) 9 { 10 int pid, p_fd[2], fd; 11 char *new_program, **new_argv; 12 char buf[BSIZE]; 13+ int r; 14 15 if (argc < 2) { 16 fprintf(stderr,"usage: %s command arg...\n",argv[0]); 17@@ -39,13 +40,13 @@ 18 } 19 20 close(p_fd[1]); 21- close(0); 22- dup(p_fd[0]); 23- close(p_fd[0]); 24 25 fd = open(argv[1],O_WRONLY|O_CREAT|O_TRUNC,0644); 26- while (read(p_fd[0],buf,BSIZE) != 0) { 27- write(fd,buf,BSIZE); 28+ while ( ( r = read(p_fd[0],buf,BSIZE) ) > 0) { 29+ write(fd,buf,r); 30+ } 31+ if ( r < 0 ) { 32+ perror( "read" ); 33 } 34 close(fd); 35

投稿2020/07/13 07:54

hidezzz

総合スコア1248

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tukareta

2020/07/13 14:42

回答ありがとうございます.直接読み込む方法もあるのですね,今後forkを複数回用いる仕様を考えるときに参考にさせていただきます.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問