在python里可以通过os.popen()和os.system()执行shell命令,C代码里自然也有相应的接口。
如下一段代码:
1 /*
2 ** sample program by virHappy
3 */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <stdarg.h>
9
10 #define MAX_BUF_LEN 8192
11
12 /*
13 ** conbine some string together accroding to the formate.
14 */
15 static inline char* do_combin_str(unsigned int max_len, const char *format, ...)
16 {
17 int n;
18 char *str = NULL;
19 va_list args;
20
21 if ((str = malloc(max_len)) == NULL) {
22 fprintf(stderr, "malloc failed\n");
23 exit(-1);
24 }
25
26 va_start(args, format);
27 n = vsnprintf(str, max_len, format, args);
28 va_end(args);
29
30 if (n >= max_len) {
31 free(str);
32 fprintf(stderr, "vsnprintf error!\n");
33 exit(-2);
34 }
35
36 return str;
37 }
38
39 /*
40 ** execute the shell commond with popen
41 */
42 int run_sh_cmd(char* cmd)
43 {
44 FILE *fp;
45 int ret = 0;
46 if (!cmd) {
47 fprintf(stderr, "cmd is NULL\n");
48 return -1;
49 }
50
51 if ((fp = popen(cmd, "r")) == NULL) {
52 fprintf(stderr, "popen error\n");
53 return -2;
54 }
55
56 ret = pclose(fp);
57 return ret;
58 }
59
60 int main(int argc, char** argv)
61 {
62 if (argc != 2 ){
63 fprintf(stderr, "error!\nUsage:%s \"cmd\" \n", argv[0]);
64 fprintf(stderr, "Sample Usage: %s \"touch file\" \n", argv[0]);
65 exit(-1);
66 }
67
68
69 char* cmd = do_combin_str(MAX_BUF_LEN,"%s",argv[1]);
70 if ( run_sh_cmd(cmd) < 0 ) {
71 fprintf(stderr, "error in run_sh_cmd\n");
72 exit(-3);
73 }else {
74 printf("success!\n");
75 }
76
77
78 return 0;
79 }
这里特意用了va_xxx函数,按照程序逻辑,使用snprintf也是可以的。
PS:
如何处理popen中命令执行失败的情况(不因为popen自身分配内存或者pipe失败)呢?
查了下man手册,对于popen的返回值是这样描述的:
man的输出
RETURN VALUE
The popen() function returns NULL if the fork(2) or pipe(2) calls fail, or if it cannot allocate memory.
The pclose() function returns -1 if wait4() returns an error, or some other error is detected.
ERRORS
The popen() function does not set errno if memory allocation fails. If the underlying fork() or pipe() fails, errno is set
appropriately. If the type argument is invalid, and this condition is detected, errno is set to EINVAL.
If pclose() cannot obtain the child status, errno is set to ECHILD.
设置场景: 执行rmdir命令, 删除的目录对象里面有文件。 如手动创建一个目录tdir, 在tdir里面创建文件,然后执行./rsc "rmdir tdir": (rsc为上面代码的目标文件)
[root@host]# ./rsc "rmdir tdir"
rmdir: tdir: Directory not empty
success!
这里popen执行成功,pclose也执行成功,但实际上dir并没有删除掉,这种情况有办法处理吗?
留意到popen出错时会设置errno,当遇到这种情况时,popen并不返回NULL,不设置errno。
续:
popen只负责执行程序,对于这种情况,由于rmdir这个命令自身不能删除空的目录,popen是检测不到的(?)。
可以通过rm -rf 替换rmdir命令。