Linux下system () 函数详解简介,system()与execl()的区别,popen()

文章详细介绍了Linux环境下system函数、popen函数和execl函数的使用和区别。system函数通过fork和execl实现命令执行,会在原进程基础上创建新进程。popen提供更简单的接口,用于读写进程的输入/输出,返回值简洁明了。而execl函数族用于替换当前进程的内存空间,不创建新进程。文章还给出了相关代码示例和应用场景。


目录

Linux下system () 函数详解简介

Linux进程 system函数 popen函数详解 ——进程完结篇

system函数的使用

popen函数的使用
linux下system 和exec 函数的区别

注意区分:execl() 函数 与 excel表格

----------------------------------

在linux系统下,system函数是execl函数的封装版

popen()函数较于system()函数的优势在于使用简单,popen()函数只返回两个值:成功 /失败

linux版 system函数的源码:

=======================


Linux下system () 函数详解简介

https://blog.csdn.net/linluan33/article/details/8097916

System与exec的区别

1、system()和exec()都可以执行进程外的命令,system是在原进程上开辟了一个新的进程,但是exec是用新进程(命令)覆盖了原有的进程

2、system()和exec()都有能产生返回值,system的返回值并不影响原有进程,但是exec的返回值影响了原进程

popen()

system()函数用起来很容易出错,返回值太多,而且返回值很容易跟command的返回值混淆。这里推荐使用popen()函数替代,关于popen()函数的简单使用也可以通过上面的链接查看。

popen()函数较于system()函数的优势在于使用简单,popen()函数只返回两个值:
成功返回子进程的status,使用WIFEXITED相关宏就可以取得command的返回结果;
失败返回-1,我们可以使用perro()函数或strerror()函数得到有用的错误信息。

Linux进程 system函数 popen函数详解 ——进程完结篇

Linux进程相关函数

system函数的使用

先看linux版system函数的源码:
代码:

#include
#include
#include
#include

int system(const char * cmdstring)
{
  pid_t pid;
  int status;

  if(cmdstring == NULL){
      
      return (1);
  }


  if((pid = fork())<0){

        status = -1;
  }
  else if(pid == 0){
    execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
    -exit(127); //子进程正常执行则不会执行此语句
    }
  else{
        while(waitpid(pid, &status, 0) < 0){
          if(errno != EINTER){
            status = -1;
            break;
          }
        }
    }
    return status;
}

通过源码可以看出,在linux系统下,system函数是execl函数的封装版
文中的 "sh -c ps"和我们所使用的"ps"是完全等价的。system调用execl函数来执行相关指令
这为我们提供了极大的便利

#include <stdio.h>
#include <stdlib.h>
int main()
{
   system("top");
   printf("\n");
}

   

这样就可以直接执行top指令

我们运用一个测试文件

#include <stdio.h>
int main(int argc,char *argv[])
{
  int i;
  for(i=0;i<argc;i++){
     printf("argv[%d]:%s\n",i,argv[i]);
  }
  return 0;
}

    

用system函数来执行它

#include <stdio.h>
#include <stdlib.h>
int main()
{
   system("./test aa bb cc dd");
   printf("\n");
}                        

效果如下:

    argv[0]:./test
    argv[1]:aa
    argv[2]:bb
    argv[3]:cc
    argv[4]:dd

popen函数的使用

FILE * popen(conste char * command, const char * type);

type:可使用“r”或者"w",分别代表读取及写入,但由于popen是以创建管道的方式创建进程连接到子进程的标准输出设备或标准输入设备,因此其带有管道的一些特性,同一时刻只能定义为写或者读。

command:如其名,单纯是一个命令字符串指针。

返回值:文件指针,函数执行成功返回文件指针,否则返回NULL。

popen特点是会将读取到的内容放入一个文件缓冲区,需要时我们而已打印出来

#include <stdio.h>
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
int main()
{
  char ret[1024];//文件缓冲区
  FILE *fp;//文件流
  fp = popen("ps -l","r");
 int size =  fread(ret,1,1024,fp);
  printf("%d%s\n",size,ret);
}

效果如下:

————————————————
版权声明:本文为CSDN博主「pg_hj」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_69980680/article/details/128376101

linux下system 和execl 函数的区别

今天学到了exec 函数族,发现函数功能就是调用系统的二进制程序或者一些脚本文件,此函数族函数一大堆,可是仔细想想实现的功能和前面的system函数没什么区别,感觉system函数方便多了,为何还要exec弄一大堆呢?肯定是有原因的啦!

小结两点区别关系:

1.system会新起一个子进程来调用要执行的命令。

         

而exec只是用另一个新程序替换了当前进程的正文、数据、堆和栈段。

即:调用exec程序不会创建新进程,调用system会创建新进程

         

2.system底层就是exec

1. system与execl的区别

system会新起一个子进程来调用要执行的命令。而exec只是用另一个新程序替换了当前进程的正文、数据、堆和栈段。

system源码:

int system(const char * cmdstring){
    pid_t pid;
    int status;
    if(cmdstring == NULL){
        return (1);
    }
    if((pid = fork())<0){
        status = -1;
    }else if(pid == 0){
        execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);//底层就是execl
        exit(127); //子进程正常执行则不会执行此语句
    }else{
     while(waitpid(pid, &status, 0) < 0){
          if(errno != EINTER){
              status = -1;
              break;
          }
     }
    }
    return status;
}

waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程结束。
如果执行成功则返回子进程识别码(PID) ,如果有错误发生则返回-1.


-----------------------------------
linux下system和execl函数的区别
https://blog.51cto.com/u_15798167/5689462

Linux中execl函数详解与日常应用(附图解与代码实现)

目录

execl函数

exec函数族的日常应用

1.Linux中第一个终端的创建

2.终端下.c文件的执行

exec其实并不是一个函数,而是由六个以exec开头的函数所构成的一个函数,如下图所示

exec函数族成员函数

execl     execle     execlp
execv    execve    execvp

其中execl函数是最常用的函数,我们就来说一下execl函数
execl函数
头文件    #include<unistd.h>
功能    为进程重载0-3G的用户空间,可与fork函数搭配使用
语法    int execl("绝对路径", “标识符”,  “需要的参数”(需要多少传入多少) ,NULL);
返回值    成功的话无返回值,失败的话返回 -1

我们来说明一下execl函数所需要的四个参数
参数    变量类型    解释
绝对路径    const char*    文件存储的绝对路径,可通过pwd命令查看
标识符    const char*    ①
参数    ------    ②
NULL    ------    最后这个必须传NULL,否则函数会报错

    ①标识符可以理解为编程时使用的“名字”,像命令 ls -a 中的ls就是标识符,是这个命令的“名字”,文件的文件名就是标识符,是这个文件的“名字”。

    ②参数很好理解,像命令 ls -a 中的 -a 就是参数,函数move(int a, int b)中的整型变量a和整形变量b就是参数

我们下面来写一个代码

所用函数:execl函数、fork函数

功能:创建三个子进程,并分别对三个子进程进行重载,第一个子进程实现使用火狐浏览器打开百度网页,第二个子进程创建一个名为huala的文件,第三个子进程显示当前目录下的文件,下图为使用火狐浏览器打开百度网页的大概流程,其余两个子进程类似该步骤

     父进程通过fork函数创建子进程,子进程调用execl函数重载用户空间,来实现三个功能,以下是代码实现

    #include<stdio.h>
    #include<unistd.h>
    #include<stdlib.h>
    #include<string.h>
     
    int main(void)
    {
        pid_t pid;
        int i;
        for (i = 0; i < 3; i++)
        {
            pid = fork();
            /*
            这个地方要判断pid是否为0是因为fork函数的实现原理,fork函数最后的return 0是子进程进行
            的,所以进入这个判断的是子进程,而子进程返回的pid就是0,如果这个地方不加上该判断,子进
            程也会进入该for循环来创造进程,子又生孙孙又生子,而我们只希望父进程来创建三个子进程,
            所以加上了该判断
            */
            if (pid == 0)
            {
                break;
            }
        }
        /*
        首先父进程进入下面的三个判断,因为父进程pid大于0,所以会进入第一个判断,打印出父进程的
        pid,然后我们用while循环一直sleep(1)来阻塞父进程,让子进程进入三个判断,因为子进程的pid
        是0,所以会进入第二个判断,第一个子进程先进入判断,进入if(i == 0)用execl函数重载来实现功
        能,firefox是命令标识符,www.baidu.com是参数,后面执行同样的步骤,也是父进程先进入判断,
        之后两个进程分别进入判断并使用execl函数重载来实现功能
        */
        if (pid > 0)
        {
            printf("parent pid %d\nsleeping..\n", getpid());
            while (1)
            {
                sleep(1);
            }
        }
        else if (pid == 0)
        {
            if (i == 0)
            {
                printf("child no.%d pid %d exec firefox..\n", i, getpid());
                execl("/usr/bin/firefox", "firefox", "www.baidu.com", NULL);
            }
            if (i == 1)
            {
                printf("child no.%d pid %d touch files..\n", i, getpid());
                execl("/usr/bin/touch", "touch", "huala", NULL);
            }
            if (i == 2)
            {
                printf("child no.%d pid %d exec ls -l..\n", i, getpid());
                execl("/bin/ls", "ls", "-l", NULL);
            }
        }
     
        return 0;
    }

这样我们就实现了我们所想要达到的功能,记住exec函数一定要在fork函数之后执行


exec (l/l? v/v?) 函数的日常应用

其实exec在linux中的应用非常的广泛,就比如第一个终端的创建,还有终端下.c文件的执行,我们讲解一下这两个过程中exec函数族的应用


1.Linux中第一个终端的创建

     具体过程:

        init(1)是系统启动初始化后的第一个进程
        当init进程初始化完成后系统会进行硬件检测,之后系统调用login函数
        检查存放在/etc/passwd中的密码与用户输入的密码是否一致,一致的话init进程就调用fork函数创建子进程
        子进程调用execl函数将子进程重载成bash终端,这样就实现了终端的创建

2.终端下.c文件的执行

 在bash终端下我们先写一个world.c文件,然后将编译后的文件命名为app,看一下这个编译后的文件和bash终端的亲缘关系,我们可以通过命令 ps -ef|grep [进程名] 来查看对应该进程名的进程id与父进程id,大概流程如下

注意:

第一个数据是用户名,第二个数字是进程id,第三个数字是父进程id

我们可以发现,app的父进程就是bash终端,那么这是为什么呢?

    原因就是bash终端调用了fork函数创建了一个子进程,子进程调用了execl函数,将文件app重载到了子进程中,所以app的父进程就是bash终端

今天的学习记录到此结束啦,咱们下篇文章见,ByeBye!
————————————————
版权声明:本文为CSDN博主「_才疏学浅_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_53133879/article/details/125092300

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值