C++ プログラムでシステムのコマンド ラインを使用する場合、基本的なプロセスは、サブプロセスを作成し、サブプロセスにシェル コマンド ラインの実行を完了させることです。
より直接的な方法は、最初に fork() を介して子プロセスを作成し、次に子プロセス内の exec 一連の関数を介してコマンド ラインを実行することです。
強力な popen 関数は上記の関数を統合し、親プロセスと子プロセスの間にパイプラインを作成します。これにより、親プロセスは読み取り操作と書き込み操作を実行できます。
序章
ヘッドファイル
#include <stdio.h>
関数プロトタイプ
FILE *popen(const char *command, const char *type)
関数 関数
file = popen(cmd,"r");
popen() は fork() を呼び出して子プロセスを生成し、子プロセスから /bin/sh -c を呼び出してパラメーター コマンドの命令を実行します。パラメーターの型は、"r" を使用して読み取りを表し、"w" を使用して書き込みを表すことができます。タイプが "r" の場合、ファイル ポインタはコマンドの標準出力に接続され、コマンドの標準出力が読み取られ、タイプが "w" の場合、ファイル ポインタはコマンドの標準入力に接続されます。コマンド、およびコマンドの標準入力が書き込まれます。
popen() は、この型の値に従って、子プロセスの標準出力デバイスまたは標準入力デバイスに接続されたパイプラインを確立し、ファイル ポインタを返します。プロセスは、このファイル ポインタを使用して、子プロセスの標準出力デバイスから読み書きできます。
ルーティーン
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
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 <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
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<FILE, 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
この圧縮ファイルには、最後のフォルダーのみが保存されます。