Szukam sposobu na uzyskanie danych wyjściowych polecenia, które jest uruchamiane z poziomu programu C ++. Patrzyłem na użycie system()
funkcji, ale to po prostu wykona polecenie. Oto przykład tego, czego szukam:
std::string result = system("./some_command");
Muszę uruchomić dowolne polecenie i uzyskać jego wynik. Spojrzałem na boost.org , ale nie znalazłem niczego, co dałoby mi to, czego potrzebuję.
/programming/52164723/how-to-execute-a-command-and-get-return-code-stdout-and-stderr-of-command-in-c
dla rozszerzenia świetnej odpowiedzi poniżej, która zawiera metody uzyskiwania,return code
astderr
także,stdout
że ta odpowiedź już wyjaśniaOdpowiedzi:
Wersja wcześniejsza niż C ++ 11:
Wymień
popen
ipclose
ze_popen
i_pclose
dla Windows.źródło
result += buffer
, dlatego rura może nie zostać poprawnie zamknięta.int main(){ puts("ERROR"); }
.Pobieranie zarówno stdout, jak i stderr (a także pisanie do stdin, nie pokazano tutaj) jest łatwe z moim nagłówkiem pstreams , który definiuje klasy iostream, które działają jak
popen
:źródło
popen
wymaga użycia interfejsu API stdio, wolę interfejs API iostreams.popen
wymaga ręcznego wyczyszczeniaFILE
uchwytu, pstreams robi to automatycznie.popen
akceptuje tylkoconst char*
argument argumentu, który wymaga ostrożności, aby uniknąć ataków polegających na wstrzyknięciu powłoki, pstreams pozwala przekazać wektor ciągów podobnych doexecv
, co jest bezpieczniejsze.popen
daje ci tylko fajkę, pstreams mówi PID dziecka, pozwalając ci wysyłać sygnały, np. zabić go, jeśli jest zablokowany lub nie wychodzi. Wszystkie te zalety, nawet jeśli chcesz tylko jednokierunkowego We / Wy.pstreambuf::in_avail()
, więc nie będzie blokować. Pozwala to na demultipleksowanie na standardowym i standardowym procesie, ponieważ każdy ma dostępne dane.pstreambuf::in_avail()
działa tylko w 100% niezawodnie, jeśli system operacyjny obsługuje niestandardowy ioctl FIONREAD, ale jest on obsługiwany w (przynajmniej) GNU / Linux i Solaris.Chciałbym użyć popen () (++ Waqas) .
Ale czasami potrzebujesz czytania i pisania ...
Wygląda na to, że nikt już nie robi trudnych rzeczy.
(Zakładając, że środowisko Unix / Linux / Mac, a może Windows z warstwą kompatybilności z POSIX ...)
Możesz także pobawić się odczytami select () i nieblokującymi.
źródło
execlp
wywołaniu jest błąd: ostatniarg
przekazany wskaźnik musi(char *) NULL
poprawnie zakończyć listę argumentów variadic (patrzexeclp(3)
odnośnik).Dla Windowsa,
popen
również działa, ale otwiera okno konsoli - które szybko miga nad aplikacją interfejsu użytkownika. Jeśli chcesz być profesjonalistą, lepiej wyłączyć to „flashowanie” (szczególnie jeśli użytkownik końcowy może to anulować).Oto moja własna wersja dla systemu Windows:
(Ten kod jest częściowo rekombinowany z pomysłów napisanych w przykładach The Code Project i MSDN).
źródło
wchar_t
iCreateProcessW
za niepotrzebne ograniczenie.The Unicode version of this function, CreateProcessW, can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). If this parameter is a constant string, the function may cause an access violation.
więc może lepiej najpierw skopiować wiersz poleceń do osobnego bufora, aby zapobiec zmianie pierwotnego wejścia programu wywołującego.Dwa możliwe podejścia:
Nie sądzę, że
popen()
jest częścią standardu C ++ (jest to część POSIX z pamięci), ale jest dostępna w każdym systemie UNIX, z którym pracowałem (i wydaje się, że celujesz w UNIX, ponieważ twoje polecenie jest./some_command
).Jeśli nie ma takiej możliwości
popen()
, możesz użyćsystem("./some_command >/tmp/some_command.out");
, a następnie użyć normalnych funkcji we / wy do przetworzenia pliku wyjściowego.źródło
Nie mogłem zrozumieć, dlaczego brakuje popen / pclose w Code :: Blocks / MinGW. Więc obejrzałem ten problem, używając zamiast tego CreateProcess () i CreatePipe ().
Oto rozwiązanie, które zadziałało dla mnie:
źródło
CREATE_NO_WINDOW
?ListStdErr
nigdy nie jest używany.Poniższe może być rozwiązaniem przenośnym. Jest zgodny ze standardami.
źródło
tmpnam
jest niebezpieczne, lepsze użyciemkstemp
”Zakładając POSIX, prosty kod do przechwytywania standardowego:
Dodatki do kodu są mile widziane dla większej funkcjonalności:
https://github.com/ericcurtin/execxx
źródło
Dane wyjściowe można uzyskać po uruchomieniu skryptu za pomocą potoku. Używamy rur, gdy chcemy uzyskać wynik procesu potomnego.
Oto skrypt, który chcesz uruchomić. Umieść go w zmiennej polecenia wraz z argumentami, które pobiera twój skrypt (nic, jeśli nie ma żadnych argumentów). I plik, w którym chcesz przechwycić dane wyjściowe skryptu, umieść je w copy_fp.
Więc popen uruchamia twój skrypt i umieszcza dane wyjściowe w fpipe, a następnie możesz po prostu skopiować wszystko z tego do pliku wyjściowego.
W ten sposób możesz uchwycić wyniki procesów potomnych.
I innym procesem jest to, że możesz bezpośrednio umieścić
>
operatora tylko w poleceniu. Więc jeśli umieścimy wszystko w pliku podczas wykonywania polecenia, nie będziesz musiał niczego kopiować.W takim przypadku nie ma potrzeby używania rur. Możesz użyć just
system
, a to uruchomi polecenie i umieści dane wyjściowe w tym pliku.Możesz przeczytać samouczek YoLinux: Sterowanie widelcem, wykonaniem i procesem, aby uzyskać więcej informacji.
źródło
Zauważ, że możesz uzyskać dane wyjściowe, przekierowując dane wyjściowe do pliku, a następnie czytając je
Pokazano to w dokumentacji
std::system
Możesz otrzymać kod wyjścia, wywołując
WEXITSTATUS
makro.źródło