exec族函数,system函数,popen函数的用法

  • exec族函数
    • 作用
    • 函数原型
    • 返回值
    • 参数说明
    • 用demo来验证exec族函数的用法
      • execl(const char *path,const char *arg,...)
      • execlp()
      • 其他的exec族函数
  • system函数
    • 用demo来验证system()的作用
  • popen函数

exec族函数

作用

我们一般使用fork()来创建一个新的进程,在新进程里面如果说我们想要执行另外一个程序,使用exec族函数是一个解决方法。当新进程调用exec族函数的时候,进程原来的程序就会被替换成新的程序。这个过程中是没有创建新的进程的,进程前后的pid也是不变的。

函数原型

#include<stdio.h>
int execl(const char *path, const char *arg, …);
int execlp(const char *file, const char *arg, …);
int execle(const char *path, const char *arg,…, char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);

返回值

exec族函数调用成功之后并不会返回值,但是如果调用失败时,会自动设置error值并返回-1,然后在原程序的断点处继续运行。

参数说明

path: 可执行文件的路径
arg:可执行文件的参数,最后必须以NULL结尾
file:如果参数file中包含/,则就将其视为路径名,否则就按 PATH环境变量,在它所指定的各目录中搜寻可执行文件。

用demo来验证exec族函数的用法

execl(const char *path,const char *arg,…)

此demo采用的开发环境是ubuntu20.04

  1. 先写一个C程序demo.c,该C程序可以用来获取命令行输入的参数。
#include<stdio.h>
int main(int argc,char *argv[]){int i = 0;for(i=0;i<argc;i++){printf("argv[%d] : %s\n",i,argv[i]);}
}

运行结果:
命令行输入:
gcc demo.c -o echoarg
./echoarg aa bb
输出结果:
argv[0]=./echoarg
argv[1]=aa
argv[2]=bb

  1. 写demo2.c来验证execl()
#include<stdio.h>
#include<unistd.h>
int main(){printf("before execl...\n");if(execl("./echoarg","echoarg","abc",NULL)==-1){printf("execl failed!\n");}printf("after execl...\n");return 0;
}

运行结果
命令行输入:
gcc demo2.c
./a.out
输出结果:
before execl…
argv[0]:echoarg
argv[1]:abc

可以看到,当demo2.c调用execl()之后,在第一个输出语句执行完之后,就直接执行了由demo.c编译而成的可执行文件echoarg。并把最后应该输出的after execl…给去掉了。这就可以证明上面说的:当新进程调用exec族函数的时候,进程原来的程序就会被替换成新的程序

execlp()

我们先把上面的demo2.c复制成demo3.c,然后稍微改一下

#include<stdio.h>
#include<unistd.h>
int main(){printf("before execl...\n");if(execl("ps","ps","-l",NULL)==-1){printf("execl failed!\n");}printf("after execl...\n");return 0;
}

命令行输入:
gcc demo3.c
./a.out
输出结果:
before execl…
execl failed!
after execl…

说明execl()函数调用失败。

原因就是execl()函数的第一个参数没有包含路径,程序找不到可执行文件。
怎么解决这个问题呢?有两种解决方法

  1. 第一种:改变环境变量(建议最好不要用)
    1.1. 首先先查看环境变量:
    命令行命令:$echo PATH
    这个时候终端就会显示环境变量
    1.2. 将需要该路径名写入环境变量
    命令行命令:export PATH=""

  2. 第一种:将execl()换成execlp()
    将前面的demo3.c复制成demo4.c

#include<stdio.h>
#include<unistd.h>
int main(){printf("before execl...\n");if(execlp("ps","ps","-l",NULL)==-1){printf("execl failed!\n");}printf("after execl...\n");return 0;
}

命令行输入:
gcc demo4.c
./a.out
输出结果:
before execl…
(ps的结果,这里就省略了)

这就说明:execlp()可以通过环境变量PATH来查询可执行文件

其他的exec族函数

其他的函数用到的几率不多,后期用到的时候可以直接查阅相关文档。
这里就不多介绍了!

system函数

有了execl族函数的基础,到了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);-exit(127); //子进程正常执行则不会执行此语句}else{while(waitpid(pid, &status, 0) < 0){if(errno != EINTER){status = -1;break;}}}return status;
}

分析一下代码,大概流程是这样的

  1. 首先,先判断参数是否为空
  2. 用fork()创建新进程,根据fork()的返回值判断当前进程为子进程还是父进程还是调用失败。
  3. 如果当前进程为子进程,则在命令行中执行参数cmdstring代表的命令,若在调用sh -c cmdstring命令时失败,就会返回-127,别的原因就返回-1;如果为父进程,则等待子进程执行完毕;如果调用失败,将状态码复赋值为-1.

用demo来验证system()的作用

demo5.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{pid_t pid;int data = 10;while(1){printf("Please input a data\n");scanf("%d",&data);if(data == 1){int fdSrc;pid = fork();if(pid >0){wait(NULL);}if(pid == 0){system("./changData");}}else{printf("wait,do nothing\n");}}return 0;
}

当键盘输入1时,用fork()创建一个新进程。fork()会返回两次值,一次是父进程,一次是子进程。当前进程为子进程时,在命令行执行./changeData,也就是另外一个可执行文件。

这里有一个老师写的博客,讲的就是linux的system函数,写的很详细:
https://www.cnblogs.com/leijiangtao/p/4051387.html

popen函数

popen()的作用就是可以保存命令行输出的结果。在linux系统,用命令man popen可以查看popen()函数的具体介绍:

NAME
popen, pclose - pipe stream to or from a process
SYNOPSIS
#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);

参数说明
command:命令行命令
type:类型
返回值
popen()函数最后返回的是一个“流”,我们需要用fread()从这个流里面获取保存的信息

直接用demo来验证一下popen
demo6.c

#include<stdio.h>
int main(){char ret[1024]={0};FILE *fp;fp = popen("ps","r");// size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);int nread = fread(ret,1,1024,fp);printf("read ret %d byte,ret=%s\n",nread,ret);return 0;
}

命令行输入:
gcc demo6.c
./a.out

输出结果:
read ret 151 byte,ret= PID TTY TIME CMD
110801 pts/2 00:00:00 bash
114116 pts/2 00:00:00 a.out
114117 pts/2 00:00:00 sh
114118 pts/2 00:00:00 ps

Linux学习笔记-exec族函数,system函数,popen函数的用法相关推荐

  1. 学习笔记——exec族函数详解(execl, execlp, execle, execv, execvp, execvpe )

    exec族函数的定义 定义 exec函数族提供了一个在进程中启动另一个程序执行的方法.它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段.代码段和堆栈段,在执行完之后,原调用 ...

  2. 【Linux学习笔记④】——Shell程序设计【变量 输入与输出 条件表达式 判断语句 循环语句 Shell函数】

    ⌛️ 文章目录 一.Shell 概述 二.Shell 脚本的定义与执行 2.1 Shell 脚本的定义 2.2 Shell 脚本的执行 三.Shell 变量 3.1 用户自定义变量 3.2 环境变量 ...

  3. 【初阶】unity3d官方案例_太空射击SpacingShooter 学习笔记 显示分数时,如何让函数之间相互交流...

    [初阶]unity3d官方案例_太空射击SpacingShooter 学习笔记 显示分数时,如何让函数之间相互交流 一.关于 显示分数时,如何让函数之间相互交流 这是一个非常好的逻辑问题 1 思路:主 ...

  4. 大数据HiveSQL学习笔记三-查询基础语法以及常用函数

    大数据HiveSQL学习笔记三-查询基础语法以及常用函数 一.基础语法 1.SELECT -列名- FROM -表名- WHERE -筛选条件- 如:需要根据城市,性别找出匹配的10个用户 user_ ...

  5. MySQL学习笔记(2)——存储过程与存储函数

    MySQL学习笔记(2)--存储过程与存储函数 文章目录 MySQL学习笔记(2)--存储过程与存储函数 一.存储过程 1.概念:预先编译好的sql语句的集合,理解成批处理语句 2.好处: 3.语法: ...

  6. 嵌入式linux学习笔记--TCP通讯整理

    嵌入式linux学习笔记–TCP通讯整理 之前的项目中使用到了比较多的tcp 通讯相关的知识,一直也没有进行整理,今天准备拿出时间好好的整理一下TCP通讯的整个过程.预计会整理linux和window ...

  7. linux添加自己的库,Linux学习笔记——例叙makefile 增加自定义共享库

    Linux学习笔记--例说makefile 增加自定义共享库 0.前言 从学习C语言开始就慢慢开始接触makefile,查阅了很多的makefile的资料但总感觉没有真正掌握makefile,如果自己 ...

  8. Linux 学习笔记16 信号量

    Linux 学习笔记16 信号量Semaphore 信号量概念 信号量(或信号灯)是一种用于提供不同进程间或一个给定进程的不同线程间同步手段的原语. 信号量是控制进程(或线程)同步(谁先执行,谁后执行 ...

  9. Linux学习笔记-随即更新-慢速学习

    Linux学习笔记 Linux系统简介 UNIX发展历史和发行版本 开源软件简介 支撑互联网的开源技术 Linux应用领域 Linux学习方法 Linux系统安装 给初学者的建议 学习linux的注意 ...

  10. 迅为嵌入式Linux学习笔记4——进程

    迅为嵌入式Linux学习笔记4--进程 进程指的是正在运行的程序,是操作系统分配资源的最小单位. 进程ID 每个进程都有唯一的标识符,这个标识符就是进程ID,简称pid 进程间通信的方法 管道通信:分 ...

最新文章

  1. 其他算法-PCA主成分分析
  2. HDLBits 系列(37)此系列关于独热码的题目的疑问?
  3. 【机器学习入门到精通系列】插值与拟合
  4. 用ASP自动生成SQL数据库的安装源程序
  5. 关于文件操作的\r\n问题。
  6. 幼儿编程学java不_《终于有人说出来了——Java不适合于作为主要编程教学语言》我的看法...
  7. Cocos2d-x 3.0新引擎文件夹结构
  8. WebApp 开发中常用的代码片段
  9. 从C语言到C++的进阶之C++的非类新特性(篇三)
  10. C#:“System.Web.Mvc.Controller.File(byte[], string)”是一个“方法”,这在给定的上下文中无效
  11. 说话人识别python_基于各种分类算法的说话人识别(年龄段识别)
  12. php 字符串压缩,PHP 压缩字符串的几种方法
  13. 全民斩仙2怎么在电脑上玩 全民斩仙2电脑版玩法教程
  14. (学信网联合万方)免费论文查重
  15. 服务器端口怎么调出虚拟键盘,win10系统打开软键盘 win10怎么调出软键盘
  16. 程序员的职业病,一定要注重身体健康才是最重要的
  17. Linux下串口的配置
  18. rk3288 SDK概览
  19. 2007年 西安站 东到西开 列车时刻表
  20. 20211221:Tensorrt部署解析模型uff模型

热门文章

  1. CTSC2016滚粗记 前篇
  2. 微信小程序之滑动果冻效果
  3. 【项目】#防翟天临老师翻车神器# ——实现文本查重
  4. 达梦数据库基础篇--数据库管理工具
  5. 【回炉重造系列】之Spring AOP简介
  6. word怎么压缩文件大小,word压缩变小
  7. 97. Interleaving String
  8. Android 网易云信直播
  9. 开发Android系统应用
  10. mbp touchbar设置_新款 MBP 配备 Touch Bar 如何关机?