C或C++如何通過程序執(zhí)行shell命令并獲取命令執(zhí)行結(jié)果?
祝大家新年快樂,身體健康,工作順利,牛年大吉!
1 參考資料
1、【c/c++】如何調(diào)用【linux】shell命令行命令并獲取命令行的輸出內(nèi)容(https://blog.csdn.net/youngstar70/article/details/70305687)
2 使用說明
2.1 應(yīng)用場景
最近在實(shí)際程序開發(fā)中,需要通過程序執(zhí)行 shell 命令,并獲取命令輸出內(nèi)容。但是系統(tǒng)自帶的 system 只能返回命令執(zhí)行成功與否,不能捕獲命令輸出。
基于此,需要實(shí)現(xiàn)的需求有:
可以執(zhí)行 shell 命令;
可以獲取命令輸出內(nèi)容;
2.2 擴(kuò)展性
由于應(yīng)用場景本就廣泛,因此擴(kuò)展性較好。
此函數(shù)可以執(zhí)行任意命令,并捕獲命令輸出結(jié)果。
實(shí)際使用過程中可以把此函數(shù)作為最底層接口,然后層層封裝,實(shí)現(xiàn)自己想要的功能。
2.3 測試環(huán)境
2.3.1 Ubuntu
找到此方法時,我首先在 Ubuntu 中進(jìn)行了測試,環(huán)境如下:
系統(tǒng)版本:Ubuntu 14.04.1 LTS
系統(tǒng)版本詳細(xì)信息如下
1zhaoc@ubuntu14:~$ lsb_release -a
2No LSB modules are available.
3Distributor ID: Ubuntu
4Description: Ubuntu 14.04.1 LTS
5Release: 14.04
6Codename: trusty
系統(tǒng)內(nèi)核版本如下
1zhaoc@ubuntu14:~$ uname -a
2Linux ubuntu14 3.13.0-32-generic #57-Ubuntu SMP Tue Jul 15 03:51:08 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
gcc 版本如下
1gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1)
2.3.2 工程代碼
隨后又放到工程代碼中測試,環(huán)境如下:
系統(tǒng)內(nèi)核版本如下
1[root]#uname -a
2Linux itl 4.4.207+ #24 PREEMPT Fri Jan 29 18:09:37 CST 2021 armv5tejl GNU/Linux
gcc 版本如下
1gcc version 4.8.3 20140320 (prerelease) (Sourcery CodeBench Lite 2014.05-29)
使用 C++ 標(biāo)準(zhǔn):C++11
3 函數(shù)原型
根據(jù)參考資料,優(yōu)化后的函數(shù)原型如下
1#include <stdio.h>
2#include <string.h>
3
4#define CMD_RESULT_BUF_SIZE 1024
5
6/*
7 * cmd:待執(zhí)行命令
8 * result:命令輸出結(jié)果
9 * 函數(shù)返回:0 成功;-1 失敗;
10 */
11int ExecuteCMD(const char *cmd, char *result)
12{
13 int iRet = -1;
14 char buf_ps[CMD_RESULT_BUF_SIZE];
15 char ps[CMD_RESULT_BUF_SIZE] = {0};
16 FILE *ptr;
17
18 strcpy(ps, cmd);
19
20 if((ptr = popen(ps, "r")) != NULL)
21 {
22 while(fgets(buf_ps, sizeof(buf_ps), ptr) != NULL)
23 {
24 strcat(result, buf_ps);
25 if(strlen(result) > CMD_RESULT_BUF_SIZE)
26 {
27 break;
28 }
29 }
30 pclose(ptr);
31 ptr = NULL;
32 iRet = 0; // 處理成功
33 }
34 else
35 {
36 printf("popen %s error\n", ps);
37 iRet = -1; // 處理失敗
38 }
39
40 return iRet;
41}
查看源碼中的 popen() 、pclose() 函數(shù)原型定義如下:
1#if (defined __USE_POSIX2 || defined __USE_SVID || defined __USE_BSD || \
2 defined __USE_MISC)
3/* Create a new stream connected to a pipe running the given command.
4
5 This function is a possible cancellation point and therefore not
6 marked with __THROW. */
7extern FILE *popen (const char *__command, const char *__modes) __wur;
8
9/* Close a stream opened by popen and return the status of its child.
10
11 This function is a possible cancellation point and therefore not
12 marked with __THROW. */
13extern int pclose (FILE *__stream);
14#endif
查看源碼中的 fgets() 函數(shù)原型如下:
1/* Get a newline-terminated string of finite length from STREAM.
2
3 This function is a possible cancellation point and therefore not
4 marked with __THROW. */
5extern char *fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
6 __wur;
4 函數(shù)封裝
接口 ExecuteCMD() 對于基礎(chǔ)的使用已經(jīng)夠了,但是輸出結(jié)果是 char * 類型的,在 C++ 中實(shí)際使用起來不是很方便,為什么不直接轉(zhuǎn)換為 string 類型呢?
如果轉(zhuǎn)換為 string 類型,就可以使用 C++ 標(biāo)準(zhǔn)庫中的接口函數(shù)進(jìn)行操作了。
于是簡單封裝了一下,此處的內(nèi)聯(lián)函數(shù)實(shí)際不一定會生效。
1/*
2 * 輸入: 執(zhí)行命令
3 * 輸出: 命令執(zhí)行結(jié)果字符串
4 */
5__inline std::string SystemWithResult(const char *cmd)
6{
7 char cBuf[CMD_RESULT_BUF_SIZE] = {0};
8 string sCmdResult;
9
10 ExecuteCMD(cmd, cBuf);
11 sCmdResult = string(cBuf); // char * 轉(zhuǎn)換為 string 類型
12 printf("CMD Result: \n%s\n", sCmdResult.c_str());
13
14 return sCmdResult;
15}
5 實(shí)際測試
使用 ExecuteCMD() 函數(shù),進(jìn)行測試,測試代碼如下:
1#include <stdio.h>
2#include <string.h>
3
4#define CMD_RESULT_BUF_SIZE 1024
5
6/*
7 * cmd:待執(zhí)行命令
8 * result:命令輸出結(jié)果
9 * 函數(shù)返回:0 成功;-1 失敗;
10 */
11int ExecuteCMD(const char *cmd, char *result)
12{
13 int iRet = -1;
14 char buf_ps[CMD_RESULT_BUF_SIZE];
15 char ps[CMD_RESULT_BUF_SIZE] = {0};
16 FILE *ptr;
17
18 strcpy(ps, cmd);
19
20 if((ptr = popen(ps, "r")) != NULL)
21 {
22 while(fgets(buf_ps, sizeof(buf_ps), ptr) != NULL)
23 {
24 strcat(result, buf_ps);
25 if(strlen(result) > CMD_RESULT_BUF_SIZE)
26 {
27 break;
28 }
29 }
30 pclose(ptr);
31 ptr = NULL;
32 iRet = 0; // 處理成功
33 }
34 else
35 {
36 printf("popen %s error\n", ps);
37 iRet = -1; // 處理失敗
38 }
39
40 return iRet;
41}
42
43int main()
44{
45 char result[CMD_RESULT_BUF_SIZE]={0};
46
47 ExecuteCMD("ls -l", result);
48
49 printf("This is an example\n\n");
50 printf("%s", result);
51 printf("\n\nThis is end\n");
52
53 return 0;
54}
編譯運(yùn)行結(jié)果如下
1zhaoc@ubuntu14:~/test/11-shellCmdTest$ gcc test1.c
2zhaoc@ubuntu14:~/test/11-shellCmdTest$
3zhaoc@ubuntu14:~/test/11-shellCmdTest$
4zhaoc@ubuntu14:~/test/11-shellCmdTest$ ./a.out
5This is an example
6
7總用量 16
8-rwxrwxr-x 1 zhaoc zhaoc 8968 2月 2 19:27 a.out
9-rwxr--r-- 1 zhaoc zhaoc 1095 2月 2 19:27 test1.c
10
11
12This is end
13zhaoc@ubuntu14:~/test/11-shellCmdTest$
6 總結(jié)
學(xué)會了一個車輪,很開心。并且通過后續(xù)接口封裝,可擴(kuò)展性也很好。重點(diǎn)還是 C 語言自己的庫函數(shù)使用,比如 popen() 、pclose() 、fgets() 等。
???????????????? END ????????????????
掃描下方微信,加作者微信進(jìn)技術(shù)交流群,請先自我介紹喔。
嵌入式編程專輯 Linux 學(xué)習(xí)專輯 C/C++編程專輯 Qt進(jìn)階學(xué)習(xí)專輯 關(guān)注微信公眾號『技術(shù)讓夢想更偉大』,后臺回復(fù)“m”查看更多內(nèi)容。 長按前往圖中包含的公眾號關(guān)注
