在一个c++程序中想要使用系统的命令行,基本的流程是创建一个子进程,令该子进程去完成shell命令行的执行。
比较直接的方法是先通过fork()创建一个子进程,随后在该子进程内通过exec系列函数执行命令行。
功能强大的popen函数集成了以上的功能,并且在父子进程间创建了管道,父进程可以通过该管道进行读写操作。
头文件
#include
函数原型
FILE *popen(const char *command, const char *type)
函数功能
file = popen(cmd,"r");
popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c来执行参数command的指令。参数type可使用“r”代表读取,“w”代表写入。如果type是"r"则文件指针连接到command的标准输出,读取命令的标准输出;如果type是"w"则文件指针连接到command的标准输入,写入命令的标准输入。
依照此type值,popen()会建立管道连到子进程的标准输出设备或标准输入设备,然后返回一个文件指针。随后进程便可利用此文件指针来读取子进程的标准输出设备或是写入到子进程的标准输入设备中。
- #include
- #include
- #include
- #include
- #include
-
- void myCommand(char* cmd){
- FILE* file;
- file = popen(cmd,"r");
- while (fgets(cmd, (int)strlen(cmd), file) !=nullptr) {
- }
- pclose(file);
- }
-
- int main(int argc, const char * argv[]) {
- char cmd[2048];
- char zipName[512];
- char path[1024];
- //测试使用的是zip指令,只要把完整指令放在cmd字符数组里就行
- strcpy(zipName,"/Users/zhangzhehao/fileTest");
- strcpy(path,"/Users/zhangzhehao/fileTest");
- //将需要使用的命令行拼出来
- snprintf(cmd, 2048, "zip -r -j %s.zip %s", zipName, path);
- //将命令行作为参数
- myCommand(cmd);
- std::cout << "Hello, World!\n";
- return 0;
- }
以上例程中测试的是用zip进行压缩文件指令,实际上测试功能可以更简单些:
- #include
- #include
- #include
- #include
- #include
-
- void myCommand(char* cmd){
- FILE* file;
- file = popen(cmd,"r");
- while (fgets(cmd, (int)strlen(cmd), file) !=nullptr) {
- }
- pclose(file);
- }
-
- int main(int argc, const char * argv[]) {
- char cmd[2048];
- strcpy(cmd,"ls");
- //将命令行作为参数
- myCommand(cmd);
- std::cout << "Hello, World!\n";
- return 0;
- }
这样就可以测试ls指令了,可以展示当前目录下的所有文件。
需要注意的是,popen返回一个文件指针,通过该指针我们读取子进程的标准输出设备或是写入到子进程的标准输入设备中,也就是将cmd真正传给子进程,令子进程去执行cmd。
mycommand函数也可以写的更加健壮:
- std::string myCommand(char* cmd) {
- std::array<char, 128> buffer;
- //记录运行结果的字符串
- std::string result;
- //popen:创建一个管道,调用fork产生一个子进程,执行一个shell以运行命令开启一个进程
- //pclose:关闭标准IO流
- std::unique_ptr
decltype (&pclose)> pipe(popen(cmd, "r"), pclose); - if (!pipe) {
- result = "error";
- return result;
- }
- while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
- //记录指令行
- result += buffer.data();
- }
- return result;
- }
zip -r /Users/fileTest.zip /Users/fileTest
以上命令会将fileTest文件夹里的文件进行压缩,并以fileTest.zip的形式存放在Users文件夹下。
但是这里会出现一个问题,该fileTest.zip会将Users文件夹也加入到压缩的内容中,也就是说
fileTest.zip里的内容是:
Users文件夹->fileTest文件夹->被压缩的各种文件
大多数时候我们只想要这些内容被压缩:
fileTest文件夹->被压缩的各种文件
因此需要在命令行中增加指令“-j”。
zip -r -j /Users/fileTest.zip /Users/fileTest
这样压缩的文件里只会保存最后一个文件夹。