【Linux】popen与system函数

system函数

  • 函数原型
    #include <stdlib.h>

    int system(const char *command);

  • 函数描述
    system()调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令,此命令执行完后随即返回原调用的进程。在调用system()期间SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会被忽略。 调用/bin/sh来执行参数指定的命令,/bin/sh 一般是一个软链接,指向某个具体的shell。
  • 返回值
    1>如果 exec 执行成功,即 command 顺利执行,则返回 command 通过 exit 或 return 的返回值。(注意 :command 顺利执行不代表执行成功,当参数中存在文件时,不论这个文件存不存在,command 都顺利执行)
    2>如果exec执行失败,也即command没有顺利执行,比如被信号中断,或者command命令根本不存在, 返回 127
    3>如果 command 为 NULL, 则 system 返回非 0 值.
    4>对于fork失败,system()函数返回-1。
  • 执行步骤
    1.fork一个子进程;
    2.在子进程中调用exec函数去执行command;
    3.在父进程中调用wait去等待子进程结束。
    判断一个 system 函数调用 shell 脚本是否正常结束的方法的条件应该是
  1. status != -1
    2.(WIFEXITED(status) 非零且 WEXITSTATUS(status) == 0
#include<stdlib.h>
#include<string.h>
int main()
{
  int status = 0;
  status = system("ps -l");
  if(status == -1){
         perror("system()");
         exit(1);
  }
  if(WIFEXITED(status)!=0)//正常退出
  {
    if(WEXITSTATUS(status)==0)//操作正确
      printf("run command success\n");
    else 
    {
       printf("run command fail and exit code is %d\n", WEXITSTATUS(status));
    }
  }
  else 
  {
    printf("exit code is  %d\n",  WEXITSTATUS(status));
  }
  return 0;
}

上述代码将显示 ps -l 命令的信息。

popen函数

  • 原函数
#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);

  • 概念:创建一个管道用于进程间通信,并调用shell,因为管道被定义为单向的 所以 type 参数 只能定义成 只读或者 只写, 不能是 两者同时, 结果流也相应的 是只读 或者 只写.
  • 功能:
    popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c来执行参数command的指令。这个进程必须由 pclose 关闭。

command参数:
command 参数 是 一个 字符串指针, 指向的是一个 以 null 结束符 结尾的字符串, 这个字符串包含 一个 shell 命令. 这个命令 被送到 /bin/sh 以 -c 参数 执行, 即由 shell 来执行.

type 参数 也是 一个 指向 以 null 结束符结尾的 字符串的指针
参数type可使用“r”代表读取,“w”代表写入。
依照此type值,popen()会建立管道连到子进程的标准输出设备或标准输入设备,然后返回一个文件指针。
随后进程便可利用此文件指针来读取子进程的输出设备或是写入到子进程的标准输入设备中。
返回值:
若成功则返回文件指针,否则返回NULL,错误原因存于errno中

#include<stdio.h>
#include<string.h>
#include<stdlib.h>


int main()
{
  FILE* file =NULL;
  char buf[1024] = {0};
  file=popen("cat hello.c","r");
  if(file==NULL){
    perror("popen()");
      exit(1);}
  while(fgets(buf,1024,file)!=NULL){
     fprintf(stdout, "%s", buf); }
  pclose(file);
  return 0;
}

上述代码将hello.c文件的内容显示在输出屏幕上。

区别:

1.system:在执行期间调用进程会一直等待shell命令执行完成
popen:无须等待shell命令执行完成就返回 (并行执行)
2. popen后需要调用pclose防止子进程变成”僵尸”状态。
fork :执行期间父进程等待子进程的退出码
3. system:对SIGCHLD、SIGINT、SIGQUIT都做了处理,
popen: 没有对信号做任何的处理。
4. system()调用堆信号屏蔽的原因是因为system能够及时的退出
并且能够正确的获取子进程的退出状态(成功回收子进程)。
popen()函数中没有屏蔽SIGINT、SIGQUIT的原因
是因为popen是”并行的”,不能影响其它”并行”进程。
5. system:执行shell命令最后返回是否执行成功,
popen:执行命令并且通过管道和shell命令进行通信。
6.在特权(setuid、setgid)进程中千万注意不要使用system和popen

猜你喜欢

转载自blog.csdn.net/weixin_41892460/article/details/83244473