2013-04-02 10 views
6

Chcę uzyskać ciąg wyjściowy polecenia systemu Linux, jak również stan wyjścia polecenia w programie C++. Realizuję polecenia systemu Linux w mojej aplikacji.jak uzyskać ciąg wyjściowy polecenia linux i stan wyjściowy w C++

na przykład: Command:

rmdir abcd wyjście

poleceń ciąg:

rmdir: nie można usunąć `abcd ': Nie ma takiego pliku lub katalogu

Command St ATUS:

1 (Co oznacza, że ​​komenda nie powiodło)

Próbowałem przy użyciu funkcji Linux system() co daje stan wyjściowy, a funkcję popen() który daje mi wyjściowego ciąg polecenia, ale ani funkcja podaje zarówno ciąg wyjściowy, jak i stan wyjściowy polecenia systemu Linux.

+1

Dlaczego pytanie oznaczone C, jeśli używasz C++? –

Odpowiedz

7

Łańcuch wyjściowy ma standardowe wyjście lub standardowy deskryptor błędu (odpowiednio 1 lub 2).

Musisz przekierować te strumienie (przyjrzeć dup i dup2 funkcji) do miejsca, gdzie można je odczytać (na przykład - POSIX pipe).

W C zrobiłbym coś takiego:

int pd[2]; 
int retValue; 
char buffer[MAXBUF] = {0}; 
pipe(pd); 
dup2(pd[1],1); 
retValue = system("your command"); 
read(pd[0], buffer, MAXBUF); 

Teraz masz (część) swój wyjście w buforze i kod zwrotny w retValue.

Alternatywnie można użyć funkcji z exec (tj. execve) i uzyskać wartość zwracaną z wait lub waitpid.

Aktualizacja: spowoduje przekierowanie tylko standardowego wyjścia. Aby przekierować standardowy błąd, użyj dup2(pd[1],1).

+0

Czy na pewno to działa? Myślałem, że 'system()' nie powróci, dopóki proces powłoki nie zostanie zakończony. Ponadto, jeśli wyjście dziecka jest duże, jego zapisy do 'stdout' mogą blokować, powodując zakleszczenie. Sądzę, że nie zdziwiłbym się, gdyby to działało, ponieważ dane są już w rurze, kiedy dziecko wychodzi, ale nadal może to być problem. – FatalError

+0

Może to zablokować, jeśli rozmiar wyjścia jest większy niż rozmiar potoku (domyślnie 65536 na moim komputerze). Jeśli jest to oczekiwane, najlepszym rozwiązaniem jest fork + exec. Ale jeśli nie (to znaczy, jeśli sprawa jest znana, a wielkość produkcji jest ograniczona), to po co zawracać sobie głowę? :) –

+0

Oczywiście, wystarczy. +1 dla interesującej strategii – FatalError

2

Niestety nie ma prostej i łatwej metody w języku C, aby to zrobić. Here's przykład prawidłowego odczytu/zapisu stdout/stderr/stdin procesu potomnego.

A kiedy chcesz otrzymać kod wyjścia trzeba użyć waitpid (kompletny przykład znajduje się na dole strony): przewidzianego

endID = waitpid(childID, &status, WNOHANG|WUNTRACED); 

Teraz wystarczy połączyć te dwa razem :)

jest również doskonałym wolny książka o nazwie dvanced L inux P ROGRAMOWANIE (ALP), zawierającego szczegółowe informacje na temat se rodzaje problemu dostępne here.

+0

I jest cały rozdział w http://advancedlinuxprogramming.com/ w tych kwestiach –

+0

@BasileStarynkevitch ah, ALP, całkowicie zapomniane o tym ... dodałem to, aby odpowiedzieć. – Vyktor

3

Najprostszym rozwiązaniem jest użycie system, a także przekierowanie standardowego i standardowego błędu do tymczasowego pliku, który można później usunąć.

0

możesz użyć wywołania systemowego popen, przekieruje wyjście do pliku i z pliku możesz przekierować wyjście do łańcucha. jak:

char buffer[MAXBUF] = {0}; 
    FILE *fd = popen("openssl version -v", "r"); 
    if (NULL == fd) 
    { 
     printf("Error in popen"); 
     return; 
    } 
    fread(buffer, MAXBUF, 1, fd); 
    printf("%s",buffer); 

    pclose(fd); 

Aby uzyskać więcej informacji przeczytaj man aktualizacja popen.

1

Opierając się na powyższej odpowiedzi Piotra Zierhoffera, oto funkcja, która właśnie to robi, a także przywraca stdout i stderr ich pierwotny stan.

// Execute command <cmd>, put its output (stdout and stderr) in <output>, 
// and return its status 
int exec_command(string& cmd, string& output) { 
    // Save original stdout and stderr to enable restoring 
    int org_stdout = dup(1); 
    int org_stderr = dup(2); 

    int pd[2]; 
    pipe(pd); 

    // Make the read-end of the pipe non blocking, so if the command being 
    // executed has no output the read() call won't get stuck 
    int flags = fcntl(pd[0], F_GETFL); 
    flags |= O_NONBLOCK; 

    if(fcntl(pd[0], F_SETFL, flags) == -1) { 
     throw string("fcntl() failed"); 
    } 

    // Redirect stdout and stderr to the write-end of the pipe 
    dup2(pd[1], 1); 
    dup2(pd[1], 2); 
    int status = system(cmd.c_str()); 
    int buf_size = 1000; 
    char buf[buf_size]; 

    // Read from read-end of the pipe 
    long num_bytes = read(pd[0], buf, buf_size); 

    if(num_bytes > 0) { 
     output.clear(); 
     output.append(buf, num_bytes); 
    } 

    // Restore stdout and stderr and release the org* descriptors 
    dup2(org_stdout, 1); 
    dup2(org_stderr, 2); 
    close(org_stdout); 
    close(org_stderr); 

    return status; 
}