2

I'm writing a program that needs to be able to execute a shell script provided by the user. I've gotten it to execute a single shell command, but the scripts provided will be more complicated than that.

Googling got me as far as the following code snippet:

FILE *pipe;
char str[100];

// The python line here is just an example, this is *not* about executing
// this particular line.
pipe = popen("python -c \"print 5 * 6\" 2>&1", "r");

fgets(str, 100, pipe);
cout << "Output: " << str << endl;

pclose(pipe)

So that this point str has 30 in it. So far so good. But what if the command has carriage returns in it, as a shell script file would, something like the following:

pipe = popen("python -c \"print 5 * 6\"\nbc <<< 5 + 6 2>&1", "r");

With this my goal is that str eventually have 30\n11.

To put another way, assume I have a file with the following contents:

python -c "print 5 * 6"
bc <<< 5 + 6

The argument I'm sending to popen above is the string representation of that file. I want to, from within C++, send that string (or something similar) to bash and have it execute exactly as if I were in the shell and sourced it with . file.sh, but setting the str variable to what I would see in the shell if it were executed there, in this case, 30\n11.

Yes, I could write this to a file and work it that way, but that seems like it should be unnecessary.

I wouldn't think this was a new problem, so either I'm thinking about it in a completely wrong way or there's a library that I simply don't know about that already does this.

Chuck
  • 4,662
  • 2
  • 33
  • 55
  • Well, it appears, according to someone, that I've asked a poor question. Feedback on how so would have been helpful. – Chuck Aug 02 '14 at 00:38
  • Well, it is really hard to see what you are actually asking. Especially your second example makes no sense. It's not clear what is supposed to happen when you pass `bc <<< 5+6` into `python`. Are you missing a `\"` at that point? – pmr Aug 02 '14 at 00:40
  • You can separate multiple commands with `;`, I believe. – Brian Bi Aug 02 '14 at 00:40
  • what about something like `python -c "exec(\"import sys\\nfor r in range(10): print 'test'\")"`? There is something that may help here: http://stackoverflow.com/q/2043453/3093378 – vsoftco Aug 02 '14 at 00:42
  • Another thing I don't understand: You call `fgets` only once, but expect more than one line to be in `str` as a result? – Jo So Aug 02 '14 at 00:50
  • I had misplaced a `\"`. I'm not trying to pass `bc` to `python`. The actually commands don't matter. I know I can separate the commands with semi colon, but that's not going to work for conditionals. Perhaps using concrete examples as a bad idea. I've edited the question to attempt to have more clarity. – Chuck Aug 02 '14 at 00:58
  • Jo So: That may be the answer, actually. I'm no C++ expert, as I'm sure is obvious. I'll Google how to use `fgets` to retrieve multiple lines. That's probably where my current error lies. However, I would think there would be some sort of C++ class that could do the job. – Chuck Aug 02 '14 at 01:01

1 Answers1

1

use bash -c.

#include <stdio.h>

int main()
{
    FILE *pipe = popen("bash -c \"echo asdf\necho 1234\" ", "r");
    char ch;
    while ((ch = fgetc(pipe)) != EOF)
        putchar(ch);
}

Output:

asdf
1234

(I've test on cygwin)

ikh
  • 10,119
  • 1
  • 31
  • 70