Выполнить программу из C-программы - PullRequest
8 голосов
/ 16 сентября 2008

Как мне запустить другую программу из моей C программы? Мне нужно иметь возможность записывать данные в STDIN запущенной программы (и, возможно, читать из нее STDOUT)

Я не уверен, что это стандартная функция C. Мне нужно решение, которое должно работать под Linux.

Ответы [ 6 ]

17 голосов
/ 16 сентября 2008

Вы хотите использовать popen. Он дает вам однонаправленный канал, с помощью которого вы можете получить доступ к стандартным и стандартным выводам программы.

popen является стандартом для современных Unix и Unix-подобных ОС, среди которых Linux: -)

Тип

man popen

в терминале, чтобы узнать больше об этом.

EDIT

Будет ли popen создавать однонаправленные или двунаправленные трубы, зависит от реализации. В Linux и OpenBSD , popen создает однонаправленные каналы, которые доступны только для чтения или только для записи. В OS X , FreeBSD и NetBSD popen создает двунаправленные каналы.

9 голосов
/ 17 сентября 2008

Некоторое время назад я написал пример кода C для кого-то еще, который показывает, как это сделать. Вот оно для вас:

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

void error(char *s);
char *data = "Some input data\n";

main()
{
  int in[2], out[2], n, pid;
  char buf[255];

  /* In a pipe, xx[0] is for reading, xx[1] is for writing */
  if (pipe(in) < 0) error("pipe in");
  if (pipe(out) < 0) error("pipe out");

  if ((pid=fork()) == 0) {
    /* This is the child process */

    /* Close stdin, stdout, stderr */
    close(0);
    close(1);
    close(2);
    /* make our pipes, our new stdin,stdout and stderr */
    dup2(in[0],0);
    dup2(out[1],1);
    dup2(out[1],2);

    /* Close the other ends of the pipes that the parent will use, because if
     * we leave these open in the child, the child/parent will not get an EOF
     * when the parent/child closes their end of the pipe.
     */
    close(in[1]);
    close(out[0]);

    /* Over-write the child process with the hexdump binary */
    execl("/usr/bin/hexdump", "hexdump", "-C", (char *)NULL);
    error("Could not exec hexdump");
  }

  printf("Spawned 'hexdump -C' as a child process at pid %d\n", pid);

  /* This is the parent process */
  /* Close the pipe ends that the child uses to read from / write to so
   * the when we close the others, an EOF will be transmitted properly.
   */
  close(in[0]);
  close(out[1]);

  printf("<- %s", data);
  /* Write some data to the childs input */
  write(in[1], data, strlen(data));

  /* Because of the small amount of data, the child may block unless we
   * close it's input stream. This sends an EOF to the child on it's
   * stdin.
   */
  close(in[1]);

  /* Read back any output */
  n = read(out[0], buf, 250);
  buf[n] = 0;
  printf("-> %s",buf);
  exit(0);
}

void error(char *s)
{
  perror(s);
  exit(1);
}
7 голосов
/ 16 сентября 2008
  1. Создайте две трубы с pipe(...), одну для stdin, одну для stdout.
  2. fork(...) процесс.
  3. В дочернем процессе (тот, где fork(...) возвращает 0) dup (...) конвейеры к stdin / stdout.
  4. exec[v][e] запускаемый файл программы в дочернем процессе.
  5. В родительском процессе (тот, где fork) возвращает PID дочернего элемента), выполните цикл, который читает из дочернего stdout (select(...) или poll(...), read(...)) в буфер до ребенок заканчивается (waitpid(...)).
  6. В конце концов, поставьте ребенку ввод на stdin, если он чего-то ожидает.
  7. Когда закончите close(...) трубы.
4 голосов
/ 17 сентября 2008

Я не согласен с Натаном Феллманом - другой вопрос не является дубликатом этого, хотя предмет связан.

Для простой однонаправленной связи popen () - достойное решение. Однако для двунаправленной связи он бесполезен.

IMO, imjorge (Хорхе Феррейра) дал большую часть ответа (80%?) Для двунаправленной связи - но пропустил несколько ключевых деталей.

  1. Крайне важно, чтобы родительский процесс закрыл конец чтения канала, который используется для отправки сообщений дочернему процессу.
  2. Крайне важно, чтобы дочерний процесс закрыл конец записи канала, который используется для отправки сообщений дочернему процессу.
  3. Крайне важно, чтобы родительский процесс закрыл конец записи канала, который используется для отправки сообщений родительскому процессу.
  4. Крайне важно, чтобы дочерний процесс закрыл конец чтения канала, который используется для отправки сообщений родительскому процессу.

Если вы не закроете неиспользуемые концы каналов, вы не получите разумного поведения при завершении одной из программ; например, дочерний объект может читать из своего стандартного ввода, но если конец записи канала не закрыт в дочернем элементе, он никогда не получит EOF (ноль байтов от чтения), потому что канал все еще открыт, и система считает может когда-нибудь дойти до записи в этот канал, даже если он в данный момент зависает, ожидая, что что-то из него прочитает.

Процессы записи должны учитывать, обрабатывать ли сигнал SIGPIPE, который выдается при записи в канал, где нет процесса чтения.

Вы должны знать о пропускной способности канала (зависит от платформы и может составлять всего 4 КБ) и разрабатывать программы, чтобы избежать тупика.

0 голосов
/ 16 сентября 2008

Вы можете использовать системный вызов, прочитайте manpage для системы (3)

0 голосов
/ 16 сентября 2008

Я думаю, вы можете использовать

freopen

для этого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...