1. ホーム
  2. c

[解決済み] 標準出力をファイルにリダイレクトする

2022-02-09 08:08:12

質問

bashのコマンドと同等のことをしようとしています。 ls>foo.txt をC言語で作成しました。

下のコードは、出力を変数にリダイレクトします。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

int main(){
  int pfds[2];
  char buf[30];

  pipe(pfds);

  if (!fork()) {
    close(pfds[0]);
     //close(1);//Close stdout
    //dup(pfds[1]);
    //execlp("ls", "ls", NULL);
    write(pfds[1], "test", 5); //Writing in the pipe
    exit(0);
  } else {
    close(pfds[1]);  
    read(pfds[0], buf, 5); //Read from pipe
    wait(NULL);
  }
  return 0;
}

コメント行は、リダイレクトに必要だと思われる操作について言及しています。 lsの出力をfoo.txtにリダイレクトするには、何を変更すればよいのでしょうか?

どのように解決するのですか?

あなたのコードが本質的に行っていることは、パイプを開き、プロセスをフォークし、子プロセスで(コメントされたコードで)標準出力を閉じ、パイプを標準出力に複製し、lsコマンドを実行し、(コメントされていないコードで)パイプに4バイトを書き込むということです。親プロセスでは、パイプからデータを読み込んで、子プロセスの完了を待ちます。

今度はstdoutをファイルにリダイレクトしたいと思います。open()システムコールを使ってファイルを開き、そのファイルディスクリプタをstdoutに複製することで実現できます。こんな感じです(テストしていないので、コードのバグに注意してください)。

int filefd = open("foo.txt", O_WRONLY|O_CREAT, 0666);
if (!fork()) {
  close(1);//Close stdout
  dup(filefd);
  execlp("ls", "ls", NULL);
} else {
  close(filefd);
  wait(NULL);
}
return 0;

しかし、他の回答で提案されているように、freopenを使うこともできます。

しかし、あなたのコードと私の修正したコードには、いくつかの懸念があります。

  • pipe() と open() システムコールは失敗することがあります。システムコールの失敗を常にチェックする必要があります。

  • fork()システムコールは、失敗することがあります。同上。

  • dup() の代わりに dup2() を使用できます。さもないと、stdin が開かれていない場合、最初に利用可能なファイル記述子に複製されるため、このコードは失敗します。

  • execlp()システムコールは失敗することがあります。同上。

  • wait()はシグナル(EINTR)で中断されることがあるようですね。シグナル(errno == EINTR)でシステムコールが中断された場合、再試行するようなラッパーを巻くことが推奨されます。