2

On my home Linux laptop, I like to write wrapper programs and GUI helpers for things I use frequently. However, I don't like Bash scripting very much, so I do a lot of stuff in C++. However, a lot of times, this requires me to use the system() function from the cstdlib.

This system() command is awesome, but I wanted a way to call system() and receive the stdout/stderror. The system() command only returns the return code from the command. So, in a Bash script, one can do:

myVar=$(ls -a | grep 'search string')
echo $myVar

and myVar will output whatever the stdout was for the command. So I began writing a wrapper class that will add a pipe-to-file to the end of the command, open the file, read all of the piped stdout, and return it as either one long string or as a vector of strings. The intricacies of the class are not really relevant here (I don't think anyway), but the above example would be done like this:

SystemCommand systemCommand;
systemCommand.setCommand("ls -a | grep \'search string\' ");
systemCommand.execute();
std::cout << systemCommand.outputAsString() << std::endl;

Behind the scenes, when systemCommand.execute() is called, the class ensures that the command will properly pipe all stdout/stderr to a randomly generated filename, in the current working directory. So for example, the above command would end up being

"ls -a | grep 'search string' >> 1452-24566.txt 2>&1". 

The class then goes attempts to open and read from that file, using ifstream:

std::ifstream readFromFile;
readFromFile.open(_outputFilename);
if (readFromFile.is_open()) { 
    //Read all contents of file into class member vector
    ...
    readFromFile.close();

    //Remove temporary file
    ...    
} else {
    //Handle read failure
}

So here is my main question will std::ifstream ever fail to open a recently created file in the current working directory? If so, what would be a way to make it more robust (specifically on Linux)?

A side/secondary question: Is there a very simplified way to achieve what I'm trying to achieve without using file pipes? Perhaps some stuff available in unistd.h? Thanks for your time.

Tyler Lewis
  • 881
  • 6
  • 19
  • 2
    *"will std::ifstream ever fail to open a recently created file"* - Chances are that it will (e.g. when anti-malware software still has it open for exclusive access). *"what would be a way to make it more robust"* - Properly handle errors. If this happens, inform the user about the error and exit, with the conventional non-zero return value. – IInspectable May 27 '16 at 00:13
  • 1
    Not giving up for only one failure and doing retry several times? (I'm not sure) – MikeCAT May 27 '16 at 00:20
  • 3
    Have you considered using [popen](http://linux.die.net/man/3/popen)? That way you read the output directly, and avoid writing a temp file. See also https://stackoverflow.com/questions/671461/how-can-i-execute-external-commands-in-c-linux – harmic May 27 '16 at 00:25
  • 1
    You do realize that the argument to `setCommand` is, essentially, a `bash` script, right? Why are you going through all the trouble of wrapping this in a C++ program? – chepner May 27 '16 at 01:07
  • @chepner - Yes. However, bash scripting for large programs becomes (for me) infeasible very quickly. C++ has roughly a zillion more library features than bash, for example string manipulation. – Tyler Lewis May 27 '16 at 02:27

1 Answers1

4

So here is my main question will std::ifstream ever fail to open a recently created file in the current working directory?

Yes.

  1. Mount a USB thumb drive (or some other removable media)
  2. cd to the mount
  3. Execute your program. While it's executing, remove the drive.
  4. Watch the IO error happen.

There's a ton of other reasons too. Filesystem corruption, hitting the file descriptor limit, etc.

If so, what would be a way to make it more robust (specifically on Linux)?

Make temporary files in /tmp, whose entire purpose is for temporary files. Or don't create a file at all, and use pipes for communication instead (Like what popen does, like harmic suggested). Even so, there are no guarantees; try to gracefully handle errors.

Colonel Thirty Two
  • 23,953
  • 8
  • 45
  • 85