So as the title says, I would like to run a shell command on the same shell process/instance in C and communicate with it, how can I do that? I have looked up every corner and I couldn't find an appropriate/straight to the point answer. I am not a C overlord, my answer could be dumb. Now I could use a combination of fork/exec on unix, but I'm on windows. If there is a cross platform solution, please mention it below. Thanks in advance.
Pseudocode:
SHELL shell = make_shell();
shell.run("cd desktop");
shell.run("dir");
print(shell.stdout)
CodePudding user response:
The standard library in C does not provide a way to do what you want. However, you can use a third party library, like boost::process
, which will make the communication part between your program and the sub-processes pretty portable. If you want to execute built-in shell commands, or commands using the shell, you will still need to deal with differences in the shells used on the different platforms.
The boost::process
library contains a lot of different ways of creating and communicating with sub processes (reference), both synchronously and asynchronously, so browse through the reference page to get a feeling for what it can do.
Here's a simple example that uses boost::process::system
to run the command dir
in the directory desktop
and collects the output from that command. It does not use the shell (which should generally be avoided) but uses boost::process::search_path
to find the command (in your PATH
) and executes the command directly without involving a shell:
#include <boost/process.hpp>
#include <boost/process/start_dir.hpp>
#include <iostream>
#include <string>
int main() {
namespace bp = ::boost::process;
bp::ipstream out;
bp::ipstream err;
bp::system(bp::search_path("dir"),
bp::start_dir = "./desktop",
bp::std_out > out, // collect stdout in out
bp::std_err > err, // collect stderr in err
bp::std_in < stdin); // for commands reading from stdin
// display what was collected on stdout and stderr:
std::string line;
std::cout << "stdout capture:\n";
while(std::getline(out, line)) {
std::cout << '[' << line << "]\n";
}
std::cout << "\nstderr capture:\n";
while(std::getline(err, line)) {
std::cout << '[' << line << "]\n";
}
}
Note: You need to link with boost_filesystem
and boost_atomic
for this example to work.
CodePudding user response:
I found this answer: https://stackoverflow.com/a/57096619/9282847.
It seems to be the only method which is both standard, and portable (assuming the implementation supports std::filesystem
).
Like:
#include <filesystem>
#include <iostream>
int main() {
namespace fs = std::filesystem;
const auto kDesktopPath = fs::path("~/Desktop"); // portable filepath
fs::current_path(kDesktopPath); // set CWD (This will throw on compiler explorer)
auto dir_it = fs::recursive_directory_iterator{ fs::current_path() };
for (auto& f: dir_it) {
std::cout.put('\n') << f;
}
}
Live example on compiler explorer
CodePudding user response:
you could use the system()
function to run shell commands. if you want run a another command at the same instance , first type in your command in the system function. then after your 1st command add a &&
symbol then a space then type your 2nd command.
What i mean is:
#include
#include <bits/stdc .h>
using namespace std;
int main(){
system("*your first command here? && *your second command here");
}
replace "*your first command here" and "*second command here" with your commands.