607 Stimmen

Wie führe ich einen Befehl aus und erhalte die Ausgabe des Befehls innerhalb von C++ mit POSIX?

Ich suche nach einem Weg, um die Ausgabe eines Befehls zu erhalten, wenn er aus einem C++-Programm heraus ausgeführt wird. Ich habe versucht, die system()-Funktion zu verwenden, aber das führt nur einen Befehl aus. Hier ist ein Beispiel dafür, was ich suche:

std::string result = system("./some_command");

Ich muss einen beliebigen Befehl ausführen und seine Ausgabe erhalten. Ich habe mir boost.org angesehen, aber nichts gefunden, das mir das geben würde, was ich brauche.

3 Stimmen

Auch siehe Antworten in dieser Frage: https://stackoverflow.com/questions/52164723/how-to‌​-execute-a-command-a‌​nd-get-return-code-s‌​tdout-and-stderr-of-‌​command-in-c für eine Erweiterung der großartigen Antwort unten, die Methoden zum Abrufen des Rückgabecodes und von stderr sowie stdout bereitstellt, die diese Antwort bereits erklärt.

8 Stimmen

@code_fodder Sie können einen Link zu stackoverflow.com/questions/52164723/… erstellen.

4voto

Dahai Li Punkte 41

Die Befehlsklasse verwendet system("cmd > stdout 2> stderr"), um dem Benutzer stdout und stderr sowie den Exit-Code bereitzustellen.

Testlauf:

./a.out 'ls .'
Exit-Code: 0
stdout: HelloWorld
HelloWorld.c
HelloWorld.cpp
HelloWorld.dSYM
a.out
gcc_container.bash
linuxsys
macsys
test.sh

stderr: 

#include 
#include 
#include 
#include 
using namespace std;

class Command {
    public:
        Command() {
            exit_code_ = -1;
        }

        int GetExitCode() { return exit_code_;}

        string GetStdOutStr() {return stdout_str_;}

        string GetStdErrStr() {return stderr_str_;}

        int Run(const char* cmd) {
            return Run(string(cmd));
        }

        /**
         * @brief Führe ein bestimmtes Kommando aus
         * 
         * @param cmd: Befehlszeichenkette
         * @return int: der Exit-Code des ausgeführten Befehls
         */
        int Run(string cmd) {

            // Temporäre Dateien erstellen
            char tmp_dir[] = "/tmp/stdir.XXXXXX";
            mkdtemp(tmp_dir);
            string stdout_file = string(tmp_dir) + "/stdout";
            string stderr_file = string(tmp_dir) + "/stderr";

            // Befehl ausführen "cmd > stdout_file 2> stderr_file"
            string cli = cmd + " > " + stdout_file + " 2> " + stderr_file;
            exit_code_ = system(cli.c_str());
            exit_code_ = WEXITSTATUS(exit_code_);
            stdout_str_ = File2Str(stdout_file);
            stderr_str_ = File2Str(stderr_file);

            // Temporäre Dateien löschen
            remove(stdout_file.c_str());
            remove(stderr_file.c_str());
            remove(tmp_dir);

            return exit_code_;
        }

    private:
        int exit_code_;
        string stderr_str_;
        string stdout_str_;

        /**
         * @brief Lese eine Datei
         * 
         * @param file_name: Dateipfad 
         * @return string der Inhalt der Datei.
         */
        string File2Str(string file_name) {
            ifstream file;
            stringstream str_stream;

            file.open(file_name);
            if (file.is_open()) {
                str_stream << file.rdbuf();
                file.close();
            }
            return str_stream.str();
        }
};

int main(int argc, const char* argv[]) {
    Command command;

    command.Run(argv[1]);
    cout << "Exit-Code: " << command.GetExitCode() << endl;
    cout << "stdout: " << command.GetStdOutStr() << endl;
    cout << "stderr: " << command.GetStdErrStr() << endl;
    return  command.GetExitCode();
}

3voto

Akib Azmain Punkte 1086

C++ Stream Implementierung von waqas Antwort:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

class execbuf : public std::streambuf {
    protected:
        std::string output;
        int_type underflow(int_type character) {
            if (gptr() < egptr()) return traits_type::to_int_type(*gptr());
            return traits_type::eof();
        }
    public:
        execbuf(const char* command) {
            std::array buffer;
            std::unique_ptr pipe(popen(command, "r"), pclose);
            if (!pipe) {
                throw std::runtime_error("popen() failed!");
            }
            while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
                this->output += buffer.data();
            }
            setg((char*)this->output.data(), (char*)this->output.data(), (char*)(this->output.data() + this->output.size()));
        }
};

class exec : public std::istream {
    protected:
        execbuf buffer;
    public:
        exec(char* command) : std::istream(nullptr), buffer(command, fd) {
            this->rdbuf(&buffer);
        }
};

Dieses Code fängt alle Ausgaben über stdout ab. Wenn Sie nur stderr abfangen möchten, geben Sie Ihren Befehl wie folgt ein:

sh -c '' 2>&1 > /dev/null

Wenn Sie sowohl stdout als auch stderr abfangen möchten, sollte der Befehl so aussehen:

sh -c '' 2>&1

0 Stimmen

Man muss #include hinzufügen und , fd entfernen, damit es kompiliert.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X