Home > other >  How to store command output and exitcode from terminal in a variable
How to store command output and exitcode from terminal in a variable

Time:06-21

From here I have the code that gives me the command line output and the exit code. Unfortunately I don't understand much of that operator overloading and if I try to rewrite it to the simple code I know (with global variables i.e.) I always get the wrong exit code status of 0.

So how can I modify the following code so I can store the output and the exit code status for future use?

#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <array>


struct CommandResult {
    std::string output;
    int exitstatus;

    friend std::ostream &operator<<(std::ostream &os, const CommandResult &result) {
        os << "command exitstatus: " << result.exitstatus << " output: " << result.output;
        return os;
    }
    bool operator==(const CommandResult &rhs) const {
        return output == rhs.output &&
               exitstatus == rhs.exitstatus;
    }
    bool operator!=(const CommandResult &rhs) const {
        return !(rhs == *this);
    }
};


class Command {

public:
    /**
     * Execute system command and get STDOUT result.
     * Like system() but gives back exit status and stdout.
     * @param command system command to execute
     * @return CommandResult containing STDOUT (not stderr) output & exitstatus
     * of command. Empty if command failed (or has no output). If you want stderr,
     * use shell redirection (2&>1).
     */
    static CommandResult exec(const std::string &command) {
        int exitcode = 255;
        std::array<char, 1048576> buffer {};
        std::string result;
#ifdef _WIN32
#define popen _popen
#define pclose _pclose
#define WEXITSTATUS
#endif
        FILE *pipe = popen(command.c_str(), "r");
        if (pipe == nullptr) {
            throw std::runtime_error("popen() failed!");
        }
        try {
            std::size_t bytesread;
            while ((bytesread = fread(buffer.data(), sizeof(buffer.at(0)), sizeof(buffer), pipe)) != 0) {
                result  = std::string(buffer.data(), bytesread);
            }
        } catch (...) {
            pclose(pipe);
            throw;
        }
        exitcode = WEXITSTATUS(pclose(pipe));
        return CommandResult{result, exitcode};
    }
};

int main ()
{
    std::cout << Command::exec("echo blablub") << std::endl;
}

Here is my code, the global variable is correct in the function but is overwritten afterwards.

#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <array>

int exitcode = 555;

std::string exec(const std::string cmd) {
    
    int exitcode = 255;
    std::array<char, 128> buffer {};
    std::string result;
    
    
    #ifdef _WIN32
    #define popen _popen
    #define pclose _pclose
    #define WEXITSTATUS
    #endif
    
    
    FILE *pipe = popen(cmd.c_str(), "r");
    if (pipe == nullptr) {
        throw std::runtime_error("popen() failed!");
    }
    try {
        std::size_t bytesread;
        while ((bytesread = fread(buffer.data(), sizeof(buffer.at(0)), sizeof(buffer), pipe)) != 0) {
            result  = std::string(buffer.data(), bytesread);
        }
    } catch (...) {
        pclose(pipe);
        throw;
    }    
    
    exitcode = WEXITSTATUS(pclose(pipe));
    std::cout<<exitcode<<'\n';
    return result;
}



int main (){
    exec("echo bla");
    std::cout<<exitcode<<'\n';
}

CodePudding user response:

Assuming the code provided in the article is correct and does what it should do, it is already doing all you need. The exit code and output are returned from the exec function.

You only have to use the returned CommandResult and access its members:

int main() {
   auto result = Command::exec("echo blablub");
   std::cout << result.output << "\n":
   std::cout << result.exitstatus << "\n";
}
  • Related