Linux下C程序执行shell命令并获取返回结果的方法

10 篇文章 0 订阅

Linux下的C编程有以下几种方法可以执行shell命令

  1. system()函数
  2. exec函数簇
  3. popen()函数

如果还需要获取返回结果,有两种较简单方便的方法

  1. popen()函数
  2. 匿名管道

1.system()函数

所需头文件:#include<stdlib.h>

函数原型:int system(const char *cmdstring);

                  cmdstring是一个字符指针,就是一个包含需要运行的shell命令的字符串

通过查阅《UNIX环境高级编程》,以下是system函数的一种实现方式


   
   
  1. int system(const char *cmdstring)
  2. {
  3. pid_t pid;
  4. int status;
  5. if (cmdstring == NULL)
  6. {
  7. return ( 1);
  8. }
  9. if ((pid = fork()) < 0)
  10. {
  11. status = -1;
  12. }
  13. else if (pid == 0)
  14. {
  15. execl( "/bin/sh", "sh", "-c", cmdstring, ( char *) 0);
  16. _exit( 127);
  17. }
  18. else
  19. {
  20. while (waitpid(pid, &status, 0) < 0)
  21. {
  22. if (errno != EINTR)
  23. {
  24. status = -1;
  25. break;
  26. }
  27. }
  28. }
  29. return(status);
  30. }

返回值:

  • 如果cmdstring字符指针为NULL,返回1
  • 如果fork失败或者waitpid返回除EINTR之外的错,则返回-1
  • 如果exec失败,即不能执行shell(多半是没这个命令),返回值如同shell执行了exit(127)一样,结果为32512
  • 如果fork、exec、waitpid都没有问题,shell也有这个命令,那么返回值是shell的终止状态(即执行shell命令的返回值)

注:exec失败或者shell命令执行失败,返回值会填入返回的整形状态status的8~15位,0~7位全为0,所以exit(127)的结果为32512是将127换成二进制为1111111,填入status的8~15位,则为111111100000000,换成十进制就是32512

通过以下对程序的试验,个人得出结论,命令正确执行返回0,不太肯定所有的命令,尝试了mv,cp,touch,ls命令正确返回都为0;exec执行失败,多半是没这个命令,返回32512;如果是其他正整数,代表shell命令是有的,但shell命令执行出问题,例如下图ls一个没有的文件,返回512.


   
   
  1. #include<stdio.h>
  2. int main()
  3. {
  4. int ret = 0;
  5. ret = system( NULL);
  6. printf( "ret = %d \n",ret); //ret = 1
  7. return 0;
  8. }
  9. #include<stdio.h>
  10. int main()
  11. {
  12. int ret = 0;
  13. ret = system( "exit 55");
  14. printf( "ret = %d \n",ret); //ret = 14080
  15. return 0;
  16. }
  17. #include<stdio.h>
  18. int main()
  19. {
  20. int ret = 0;
  21. ret = system( "ls dsfgsdfg"); //ls一个没有的文件 ret = 512
  22. printf( "ret = %d \n",ret);
  23. return 0;
  24. }
  25. #include<stdio.h>
  26. int main()
  27. {
  28. int ret = 0;
  29. ret = system( "asdfgdsgs"); //输入一个没有的命令 ret = 32512
  30. printf( "ret = %d \n",ret);
  31. return 0;
  32. }
  33. #include<stdio.h>
  34. int main()
  35. {
  36. int ret = 0;
  37. ret = system( "ls");
  38. printf( "ret = %d \n",ret); //正常 ret = 0
  39. return 0;
  40. }

 

2.exec函数簇

我就直接照搬我的文章《linux编程进程与线程基本实例》里的exec函数簇介绍了。

调用exec函数时,该调用ecec的进程执行的程序完全替换为新程序,但并不创建新进程,前后进程的ID并不改变。exec只是用磁盘上的一个新程序替换了当前进程的正文段、数据段、堆段和栈段。


   
   
  1. #include <unistd.h>
  2. extern char **environ;
  3. int execl(const char *path, const char *arg, ...);
  4. int execv(const char *path, char *const argv[]);
  5. int execvp(const char *file, char *const argv[]);
  6. int execve(const char *path, char *const argv[], char *const envp[]);
  7. int execlp(const char *file, const char *arg, ...);
  8. int execle(const char *path, const char *arg, ..., char * const envp[]);

最后一个参数为NULL 或者(char *)0

成功不会返回任何值,调用失败会返回-1   

const char *path要写绝对路径,const char *file就不用

例如execlp("ls","ls","-l",NULL);

execl("/bin/ls","ls","-l",NULL);

char *arg[] = {"ls", "-a", NULL}

execv( "/bin/ls",arg);

execvp( "ls",arg);

 

3.popen()函数和pclose()函数

常见操作是创建一个连接到另一个进程(shell的命令行)的管道,然后读其输出或向其输入端发送数据。

工作原理:popen先执行fork,然后调用exec执行cmdstring,并返回一个标准的I/O文件指针。

头文件:#include<stdio.h>

原型:FILE *popen(const char *cmdstring, const char *type)

cmdstring:包含shell命令字符串

type:为”r”时,则文件指针连接到cmdstring的标准输出,也就是代表指向执行shell命令返回的消息,也可以认为链接到stdout

           为”w”时,则文件指针连接到cmdstring的标准输入,也可以认为链接到stdin

            int pclose(FILE *fp);

                      fp:为ponen返回的文件指针

返回值:成功返回cmdstring的终止状态;出错返回-1

下面是执行通过popen函数执行shell命令ls的代码


   
   
  1. #include<stdio.h>
  2. int main()
  3. {
  4. FILE *fp = NULL;
  5. char data[ 100] = { '0'};
  6. fp = popen( "ls", "r");
  7. if (fp == NULL)
  8. {
  9. printf( "popen error!\n");
  10. return 1;
  11. }
  12. while (fgets(data, sizeof(data), fp) != NULL)
  13. {
  14. printf( "%s", data);
  15. }
  16. pclose(fp);
  17. return 0;
  18. }

 

4.匿名管道pipe

使用管道来获取执行shell命令返回的信息,一般流程如下

        1.创建管道

        2.使用dup函数复制描述符将shell命令行标准输出绑定到管道的写端

        3.从管道的读端读取数据

pipe函数

        所需头文件:#include<unistd.h>

        函数原型:int pipe(int fd[2]);

        返回值:成功返回0,出错返回-1

一个例子:创建进程,创建匿名管道,子进程使用dup2函数将标准输出的描述符复制给管道的写端,父进程从管道的读端读取数据


   
   
  1. #include<stdio.h>
  2. #include<unistd.h>
  3. #include<string.h>
  4. #include<stdlib.h>
  5. int main()
  6. {
  7. int fpipe[ 2] = { 0};
  8. pid_t fpid;
  9. char massage[ 1000] = { 0};
  10. memset(massage, 0, 20);
  11. if (pipe(fpipe) < 0)
  12. {
  13. printf( "Create pipe error!\n");
  14. }
  15. fpid = fork();
  16. if (fpid == 0)
  17. {
  18. close(fpipe[ 0]);
  19. dup2(fpipe[ 1],STDOUT_FILENO);
  20. system( "ls");
  21. }
  22. else if (fpid > 0)
  23. {
  24. wait( NULL);
  25. printf( "this is father,recieve:");
  26. fflush( stdout);
  27. close(fpipe[ 1]);
  28. read(fpipe[ 0], massage, 1000);
  29. printf( "%s\n",massage);
  30. }
  31. else
  32. {
  33. printf( "create fork error!\n");
  34. }
  35. return 0;
  36. }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值