c++写入shell命令
C++编程执行shell命令
本文写作用于linuxC++编程
system调用执行shell命令
使用system(“ls -l ”)执行shell命令,但其返回值为整型。返回0则为不成功执行。
#include <iostream>
int main(){
std::string cmd = "ls -l";
int ret = system(cmd.to_str());
return 0;
}
popen调用执行shell命令
使用popen调用执行命令,FILE *popen(const char *command, const char *type);,popne返回值为标准IO流,不包括标准异常的返回;且popen的输出流默认是块缓冲的;popen的实现原理为调用popen时会创建一个管道,用于父子进程之间通信;然后fork子进程,子进程调用exec执行指定命令(一般默认会用/bin/sh -c),父进程通过返回的文件指针与子进程交互;唤醒shell程序执行shell命令。支持的类型参数为读或者写模式。结果流相应为只读或者只写。command参数是一个包含shell命令的非空字符串指针,cmd通过‘/bin/sh -c’ 解释shell命令。另外需要配套使用pclose()函数等待进程终结,并返回退出状态。由于其是直接使用/bin/sh执行shell命令,所以会具有命令注入的风险。
#include <iostream>
using namespace std;
int main(){
std::string cmd = "ls -l";
FILE* stream = popen(cmd.c_str(), "r");
char buffer[128];
while (fgets(buffer, sizeof(buffer), stream)) {
cout << buffer;
}
pclose(stream);
return 0;
}
此种方式的缺点是,安全性差,可能会被串改
pipe、fork、exec组合
pipe创建管道、fork创建子进程,然后使用子进程使用execl函数执行命令
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
using namespace std;
int main(){
std::string cmd = "ls -l";
pid_t pid;
int pipefd[2];
if (pipe(pipefd)) {
perror("pipe failed");
exit(EXIT_FAILURE);
}
pid = fork(); //fork子进程,共享管道fd
if (pid == 0) { // 子进程
cout << "子进程id是" << getpid() << endl;
cout << "父进程id是" << getppid() << endl;
// 关闭读端
close(pipefd[0]);
dup2(pipefd[1], STDOUT_FILENO); // 标准输出重定向到fd
dup2(pipefd[1], STDERR_FILENO);
execl("/bin/ls", "ls", "-l", (char*)nullptr);
} else if (pid > 0) {
cout << "子进程id是" << getpid() << endl;
cout << "父进程id是" << getppid() << endl;
close(pipefd[1]); // 关闭写端
char buffer[128];
// FILE* stream = fdopen(pipefd[0],"r");
// while (fgets(buffer, sizeof(buffer), stream)) {
// cout << buffer;
// }
while (read(pipefd[0], buffer, sizeof(buffer))) {
cout << buffer;
}
close(pipefd[0]); // 关闭读端
wait(nullptr);
} else {
perror("fork failed");
exit(EXIT_FAILURE);
}
return 0;
}
封装为c++流
使用stdio_filebuf封装FILE文件流为C++文件缓冲,从而可以被istream进行初始化。
__gnu_cxx::stdio_filebuf(FILE* file, std::ios::openmode mode);
openmode支持的文件模式为:std::ios::in(读取模式),std::ios::out(写入模式),std::ios::out|std::ios::in(写入加读取模式),之后使用istream对象关联到filebuf
#include <iostream>
#include <ext/stdio_filebuf.h>
using namespace std;
int main(){
std::string cmd = "ls -l";
FILE* stream = popen(cmd.c_str(), "r");
string temp;
__gnu_cxx::stdio_filebuf<char> filebuf(stream, std::ios::in);
while (getline(istream(&filebuf), temp)) {
cout << temp << endl;
}
pclose(stream);
return 0;
}

浙公网安备 33010602011771号