Issue
As it can be done with Python.
I am interested not only in running single shell commands, but also in saving the current environment state.
For example, the following code:
system("a=2");
system("echo $a");
prints nothing, but I want to find a way by which the program would print "2".
The main goal is to keep the shell environment (that can be initialized, for example, using .bashrc) throughout the entire С/С++ program, as if you work in your terminal.
Solution
Bash does not have an API in the same sense that Python does, but it's a shell. It has a text-based UI that is relatively easy for other programs to use. You cannot use system()
because it requires you to specify all shell input up front and blocks until the shell exits, but you can use the same mechanism that system()
does: run the shell in a separate process.
Details depend on the machine on which your program runs, but on machines where you typically find Bash or another Bourne-family shell -- Linux, Mac, and other POSIX systems -- you have at least two main alternatives:
If you want the shell output to go (only) to the host program's standard output and standard error streams, then you can use
popen()
to open a stream connected to a shell:FILE *shell = popen("/bin/bash -i", "w");
You could then write an arbitrary sequence of shell commands to the stream, and the shell will receive them on its standard input, execute them, and write the results to its standard output. The shell launched this way will share the caller's standard output and standard error.
If the host program must both feed input to the shell and receive its output then you need to work at a lower level:
- Use
pipe()
to create two pipes (three if you want to capture the shell's standard error separately). fork()
a child process in which to run the shell, and in it- Back in the parent,
close()
the pipe ends the parent will not be using- send commands to the shell over the pipe set up for doing so
- read responses and / or error responses via the pipe(s)
- when done with the shell
close()
the pipes andwait()
for the child process to terminate. You can get its exit status at this point if you're interested in that.
- Use
Option (2) requires handling a lot more details -- more even than the above overview might suggest. You will find many answers here on SO that address them if you have need of that.
Answered By - John Bollinger