本篇介紹在 C/C++ 程式用 popen 來取得外部執行 shell command 指令結果(螢幕輸出字串),例如在程式裡執行 ls 指令,那我們怎麼透過 popen 獲得 ls 指令的輸出結果,請參考下面內容。
同樣是在程式裡執行 ls,來看看這幾個方式有什麼不同,
使用 system
來執行會等待system執行完(blocking),就接著往下執行了,
使用 popen
來執行不會等待執行完(non-blocking),才接著往下執行,
但是如果要讀取 popen
的執行結果就必須等待執行完成(blocking),才接著往下執行,
要記得這幾個之前差異,在使用上才能依情境挑選適合的 api 來使用。
範例. 用 popen 取得外部執行的結果
以下範例為執行一個外部指令 ls 並取讀取 ls 的輸出,將其輸出用 cout 印出來,
使用 popen 去建立一個管道 pipe,透過 fork 產生新的子行程,然後執行 ls 指令,
popen 回傳的是 FILE 類型,可以用讀取文件的方式去操作它,最後不使用時要 pclose,
其中 fgets 是每次讀取一行,也就是讀取到’\n’換行字元就會返回,
也可以換成 fread,視不同情形而定,
不斷地將讀取到的內容疊加在 result 裡最後返回,1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36// g++ cpp-get-exec-cmd-output.cpp -o a.out -std=c++11 -pthread
using namespace std;
bool shellCmd(const string &cmd, string &result) {
char buffer[512];
result = "";
// Open pipe to file
FILE* pipe = popen(cmd.c_str(), "r");
if (!pipe) {
return false;
}
// read till end of process:
while (!feof(pipe)) {
// use buffer to read and add to result
if (fgets(buffer, sizeof(buffer), pipe) != NULL)
result += buffer;
}
pclose(pipe);
return true;
}
int main() {
string result;
shellCmd("ls", result);
cout << result;
return 0;
}
有一定經驗的人都知道 popen
與 pclose
只有在 unix 系統下有,在 windows 下是沒有 popen
與 pclose
,但是有對應的函式,popen
與 pclose
在 Windows 裡對應的函式為 _popen
與 _pclose
, 詳情請看微軟官方文件
使用 C++11 的寫法
1 | TBD |
進階. 寫個像 tail 或 tee 指令的程式
tail -f
指令可以持續監控對某個檔案,該檔案一旦有新增便會將內容印出來,
tee 指令是將某指令的標準輸出重新導到檔案也順便導到標準輸出,
其訣竅在持續讀取,1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40// g++ cpp-get-exec-cmd-output2.cpp -o a.out -std=c++11 -pthread
using namespace std;
bool stop = false;
bool shellCmd(const string &cmd) {
char buffer[512];
// Open pipe to file
FILE* pipe = popen(cmd.c_str(), "r");
if (!pipe) {
return false;
}
// read till end of process:
while (!feof(pipe) || stop) {
// use buffer to read and add to result
if (fgets(buffer, sizeof(buffer), pipe) != NULL)
cout << buffer;
}
pclose(pipe);
return true;
}
int main() {
thread th1 = thread(shellCmd, "tail -f /var/log/syslog");
std::this_thread::sleep_for(std::chrono::seconds(10));
stop = true;
th1.join();
return 0;
}
不過在結束時可能會卡在 plcose 結束不了有點小缺陷,之後有時間再把它改寫吧~
參考
[1] process - How do I execute a command and get the output of the command within C++ using POSIX? - Stack Overflow
https://stackoverflow.com/questions/478898/how-do-i-execute-a-command-and-get-the-output-of-the-command-within-c-using-po
[2] How to execute a command and get the output of command within C++ using POSIX?
https://www.tutorialspoint.com/How-to-execute-a-command-and-get-the-output-of-command-within-Cplusplus-using-POSIX
有效
[3] c++11 - How to execute a command and get return code stdout and stderr of command in C++ - Stack Overflow
https://stackoverflow.com/questions/52164723/how-to-execute-a-command-and-get-return-code-stdout-and-stderr-of-command-in-c
其它相關文章推薦
C/C++ 新手入門教學懶人包
C++ std::sort 排序用法與範例完整介紹
std::queue 用法與範例
std::thread 用法與範例
C++ virtual 的兩種用法
C/C++ 判斷檔案是否存在
C++ 設計模式 - 單例模式 Singleton Pattern
C/C++ call by value傳值, call by pointer傳址, call by reference傳參考 的差別