2013-02-25 5 views
12

Я пишу программу C++, которая выполняет и выводит (в режиме реального времени) сценарий оболочки, makefile или только другую программу. Однако я хотел бы, чтобы моя программа возвращалась по-разному, когда есть ошибки или ошибки.Как захватить exit_code и stderr команды, запущенной на C++?

#include "execxi.h" 



using namespace std; 


int execXI::run(string command) 
{ 

    FILE *in; 
    char buff[512]; 
    // is this the check for command execution exited with not 0? 
    if(!(in = popen(command.c_str(), "r"))){ 
      // I want to return the exit code and error message too if any 
     return 1; 
    } 
    // this part echoes the output of the command that's executed 
    while(fgets(buff, sizeof(buff), in)!=NULL){ 
     cout << buff; 
    } 
    pclose(in); 
    return 0; 



} 

- это то, что у меня есть.

Скажем, этот сценарий побежал make построить программу, и она дала ошибку, как так

on_target_webkit_version out/Release/obj/gen/webkit_version.h 
Traceback (most recent call last): 
    File "../build/webkit_version.py", line 107, in <module> 
    sys.exit(main()) 
    File "../build/webkit_version.py", line 103, in main 
    return EmitVersionHeader(*sys.argv[1:]) 
    File "../build/webkit_version.py", line 86, in EmitVersionHeader 
    webkit_revision = GetWebKitRevision(webkit_dir, version_file) 
    File "../build/webkit_version.py", line 60, in GetWebKitRevision 
    version_info = lastchange.FetchVersionInfo(
AttributeError: 'module' object has no attribute 'FetchVersionInfo' 
make: *** [out/Release/obj/gen/webkit_version.h] Error 1 
  • это возможно для меня, чтобы знать, что эта завершилась с ошибкой?

    • Выходит ли код else than 0, так как это ошибка?

    • Это последняя деталь, выведенная в stderr?

Учитывая, что make завершался с кодом не 0, скажем 1, и выход в stderr это не возможно для меня, чтобы захватить эти коды выхода и сообщение об ошибке, в конце концов?

Как я могу получить код выхода и stderr после вывода результатов программы и вернуть exit code/stderr в функцию?

+3

pclose возвращает статус выхода. –

+0

http://jineshkj.wordpress.com/2006/12/22/how-to-capture-stdin-stdout-and-stderr-of-child-program/ –

ответ

13

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

printf("Exit code: %i\n", WEXITSTATUS(pclose(fp))); 

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

#include <unistd.h> 
#include <stdio.h> 

/* since pipes are unidirectional, we need two pipes. 
    one for data to flow from parent's stdout to child's 
    stdin and the other for child's stdout to flow to 
    parent's stdin */ 

#define NUM_PIPES   2 

#define PARENT_WRITE_PIPE 0 
#define PARENT_READ_PIPE 1 

int pipes[NUM_PIPES][2]; 

/* always in a pipe[], pipe[0] is for read and 
    pipe[1] is for write */ 
#define READ_FD 0 
#define WRITE_FD 1 

#define PARENT_READ_FD (pipes[PARENT_READ_PIPE][READ_FD] ) 
#define PARENT_WRITE_FD (pipes[PARENT_WRITE_PIPE][WRITE_FD]) 

#define CHILD_READ_FD (pipes[PARENT_WRITE_PIPE][READ_FD] ) 
#define CHILD_WRITE_FD (pipes[PARENT_READ_PIPE][WRITE_FD] ) 

void 
main() 
{ 
    int outfd[2]; 
    int infd[2]; 

    // pipes for parent to write and read 
    pipe(pipes[PARENT_READ_PIPE]); 
    pipe(pipes[PARENT_WRITE_PIPE]); 

    if(!fork()) { 
     char *argv[]={ "/usr/bin/bc", "-q", 0}; 

     dup2(CHILD_READ_FD, STDIN_FILENO); 
     dup2(CHILD_WRITE_FD, STDOUT_FILENO); 

     /* Close fds not required by child. Also, we don't 
      want the exec'ed program to know these existed */ 
     close(CHILD_READ_FD); 
     close(CHILD_WRITE_FD); 
     close(PARENT_READ_FD); 
     close(PARENT_WRITE_FD); 

     execv(argv[0], argv); 
    } else { 
     char buffer[100]; 
     int count; 

     /* close fds not required by parent */  
     close(CHILD_READ_FD); 
     close(CHILD_WRITE_FD); 

     // Write to child’s stdin 
     write(PARENT_WRITE_FD, "2^32\n", 5); 

     // Read from child’s stdout 
     count = read(PARENT_READ_FD, buffer, sizeof(buffer)-1); 
     if (count >= 0) { 
      buffer[count] = 0; 
      printf("%s", buffer); 
     } else { 
      printf("IO Error\n"); 
     } 
    } 
} 

Код здесь:

http://jineshkj.wordpress.com/2006/12/22/how-to-capture-stdin-stdout-and-stderr-of-child-program/

+1

Для меня использование 'WEXITSTATUS' с' pclose() 'возвращает' 1' для успеха и '-1' для неудачи. Правильно ли это звучит, или я сделал что-то неправильно? –

+0

@ AndyJ0076: выглядит хорошо для меня. – lpapp

+0

есть объяснение https://groups.google.com/forum/#!topic/utah-c/g4MpZVnJ7es относительно разных кодов выхода не 0 –

9

Возвращаемое значение дочернего процесса находится в верхней части 8 бит. У вас есть , чтобы разделить возвращаемое значение pclose на 256, после чего вы получите искомое возвращаемое значение дочернего процесса .

расставшись с http://bytes.com/topic/c/answers/131694-pclose-returning-termination-status-command

Мой ответ будет pclose(in)/256 это код выхода.

Я до сих пор не знаю, как захватить stderr или sdtout по-другому, но пока не будет ответа, я соглашусь с этим в качестве своего ответа.

+0

Такая же проблема здесь. Вы нашли решение своего открытого вопроса? Мое обходное решение будет направлять stderr в файл и прочитать это снова с помощью всплывающего вызова. – Strubbl

+1

@Strubbl Вид ... проверьте это https://github.com/aponxi/npm-execxi/blob/master/execxi.cpp Я написал расширение C++ для nodejs для выполнения команд оболочки. Я думаю, что я не реализовал разделение stderr и stdout, потому что не все программы, используемые stderr для ошибок, я понял. И я считаю, что я придумал что-то, чтобы предотвратить подход «писать, чем читать». Я надеюсь, что чтение того, что я сделал в этом коде, помогает (это было какое-то время, поэтому я неясен в деталях.) – Logan

+1

Вы также можете использовать перенаправление оболочки, 2> & 1 и искать сообщения об ошибках. – ChuckCottrill

0

Спасибо за ответ о выходе кода Logan.

Я считаю, туда-обратно, чтобы получить поток ошибок будет перенаправить его на временный файл:

FILE* f = popen("cmd 2>/tmp/tmpfile.txt", "r"); 
+1

Создайте уникальный выходной файл (возможно, используя pid), так что, когда вам нужно запустить 2+ копии, вы получите полезный вывод. – ChuckCottrill

+0

Используйте 'tempnam',' tmpfile' или 'tmpnam' для создания файлов с временным доступом, ** никогда ** жестко кодировать имена. – rsp

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