2015-03-19 2 views
3

Я пытаюсь сделать эквивалент команды Баш ls>foo.txt в С.Перенаправление стандартный вывод в файл

Код ниже перенаправляет вывод в переменную.

#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?

+1

Почему вы создаете трубу, когда в синтаксисе оболочки, который вы эмулируете, нет ни одной трубы? –

+0

«Эквивалент [этого кода bash] в C» не делает его вопросом bash. Только отметьте его bash, если вы хотите, чтобы люди, которые являются экспертами в bash (а не C!), Смотрели на него. –

ответ

4

Что ваш код в основном делает, так это то, что вы открываете канал, а затем разворачиваете процесс и в дочернем процессе (в прокомментированном коде) закрываете stdout, дублируете канал на stdout и выполняете команду 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, как это было предложено другой ответ.

Однако, у меня есть несколько проблем вашего кода и мой измененный код:

  • трубы() и открытые() системные вызовы могут потерпеть неудачу. Вы всегда должны проверять отказ системного вызова.

  • Системный вызов fork() может завершиться неудачно. То же самое.

  • dupo() может использоваться вместо dup(); в противном случае код будет терпеть неудачу, если stdin не открыт, поскольку он дублирует первый доступный дескриптор файла.

  • Системный вызов execlp() может завершиться с ошибкой. То же самое.

  • Я думаю, wait() может быть прерван сигналом (EINTR). Рекомендуется обернуть его вокруг обертки, которая повторяет системный вызов, если он прерывается сигналом (errno == EINTR).

4

Решая перенаправления вывода в файл, который вы можете использовать freopen().

Предполагая, что вы пытаетесь перенаправить stdout в файл «output.txt», то вы можете от записи

freopen("output.txt", "a+", stdout); 

Здесь «a+» для добавления режима. Если файл существует, файл открывается в режиме добавления. В противном случае создается новый файл.

После повторного открытия stdout с freopen() все выходные инструкции (printf, putchar) перенаправляются на 'output.txt'. Поэтому после этого любой оператор printf() перенаправит его вывод в файл 'output.txt'.

Если вы хотите возобновить поведение printf() «s по умолчанию снова (то есть печать в терминале/командной строки), то вы должны переназначить stdout снова с помощью следующей code-

freopen("/dev/tty", "w", stdout); /*for gcc, ubuntu*/ 

Или -

freopen("CON", "w", stdout); /*Mingw C++; Windows*/ 

Однако подобная техника работает для 'stdin'.

Смежные вопросы