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;
}
posted @   LemHou  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 2分钟学会 DeepSeek API,竟然比官方更好用!
· .NET 使用 DeepSeek R1 开发智能 AI 客户端
· 10亿数据,如何做迁移?
· 推荐几款开源且免费的 .NET MAUI 组件库
· c# 半导体/led行业 晶圆片WaferMap实现 map图实现入门篇
点击右上角即可分享
微信分享提示