介绍一下Linux系统中的代码执行shell等命令的几种操作方式:

一、标准流管道popen

该函数的原型是FILE * popen(const char* command, const char *type);

command:使我们要执行的命令,即上述的运行命令,

type:有两种可能的取值,“r”(代表读取)或者“w"(代表写入)

popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh-c来执行参数command的指令,参数type可使用“r”读取 或者“w”写入,根据type的值,popen()会创建管道连接到子进程的标准输出设备或者标准输入设备,然后返回一个文件指针。随后进程就可以利用此文件指针来读取子进程的标准输出设备或者写入子进程的标准输入设备。

这个函数可以大大减少代码的编写量,但使用不太灵活,不能自己创建管道那么灵活,并且popen()必须使用标准的I/o函数进行操作,也不能使用read(),wirte()这种不带缓冲的I/O函数,必须使用pclose()来关闭管道流,该函数关闭标准I/O流,并等待命令执行结束

个人总结:记住,向这个流中写内容相当于写入该命令(或者是该程序)标准输入; 向这个流中读数据相当于读取该命令(或者是该程序)的标准输出

写例子:

#include<stdio.h>

#include<unistd.h>

#include<stdlib.h>

#include<fcntl.h>

int main()

{

FILE *fp;

char *cmd="cat > aaa";   ///该命令新建一个文件,提示用户输入数据作为其内容

char buf[1000]="ni hao wo de peng you!\n";  ///待输入的参数

if((fp=popen(cmd,"w"))==NULL)

return 1;

fwrite(buf,sizeof(char),1000,fp);   ///通过文件描述符写入文件数据

pclose(fp); ///关闭文件描述符

exit(0);

return 0;

}

读例子:

LD_S32 RunSysCmd2(LD_CS8 *pCmd, LD_S8 *pRslBuf, LD_S32 bufSz)

{

LD_S32 ret = LD_FAILURE;

FILE *pFd = popen(pCmd, "r");//创建一个流管道生成一个子进程用于执行命令

if(pFd)

{

memset(pRslBuf, 0, bufSz);

if(fread(pRslBuf, bufSz - 1, 1, pFd) >= 0)//从该命令中读取数据

{

ret = LD_SUCCESS;

}

pclose(pFd);//关闭流管道

}

return ret;

}

二、system

system("cat "Read pipe successfully!" > test1")

三、exec

在Linux中,并不存在exec()函数,exec指的是一组函数,一共有6个,分别是:

#include <unistd.h>

extern char **environ;

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 execve(const char *path, char *const argv[], char *const envp[]);

其中只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数。

exec函数族的作用是根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用进程内部执行一个可执行文件。这里的可执行文件既可以是二进制文件,也可以是任何Linux下可执行的脚本文件。

exec和source都属于bash内部命令(builtins commands),在bash下输入man exec或man source可以查看所有的内部命令信息。
  bash shell的命令分为两类:外部命令和内部命令。外部命令是通过系统调用或独立的程序实现的,如sed、awk等等。内部

命令是由特殊的文件格式(.def)所实现,如cd、history、exec等等。

  在说明exe和source的区别之前,先说明一下fork的概念。

  fork是linux的系统调用,用来创建子进程(child process)。子进程是父进程(parent process)的一个副本,从父进程那里

获得一定的资源分配以及继承父进程的环境。子进程与父进程唯一不同的地方在于pid(process id)。

  环境变量(传给子进程的变量,遗传性是本地变量和环境变量的根本区别)只能单向从父进程传给子进程。不管子进程的环境

变量如何变化,都不会影响父进程的环境变量。

  shell
script:

  有两种方法执行shell
scripts,一种是新产生一个shell,然后执行相应的shell
scripts;一种是在当前shell下执行,不

再启用其他shell。

  新产生一个shell然后再执行scripts的方法是在scripts文件开头加入以下语句

  #!/bin/sh

  一般的script文件(.sh)即是这种用法。这种方法先启用新的sub-shell(新的子进程),然后在其下执行命令。

  另外一种方法就是上面说过的source命令,不再产生新的shell,而在当前shell下执行一切命令。

  source:

  source命令即点(.)命令。

  在bash下输入man source,找到source命令解释处,可以看到解释”Read and execute commands from filename in the

current shell
environment and …”。从中可以知道,source命令是在当前进程中执行参数文件中的各个命令,而不是另起子

进程(或sub-shell)。

  exec:

  在bash下输入man exec,找到exec命令解释处,可以看到有”No new process is created.”这样的解释,这就是说exec命

令不产生新的子进程。那么exec与source的区别是什么呢?

  exec命令在执行时会把当前的shell process关闭,然后换到后面的命令继续执行。

系统调用exec是以新的进程去代替原来的进程,但进程的PID保持不变。因此,可以这样认为,exec系统调用并没有创建新的

进程,只是替换了原来进程上下文的内容。原进程的代码段,数据段,堆栈段被新的进程所代替。

popen,system和exec区别:

1.system和popen都是执行了类似的运行流程,大致是fork->execl->return。但是我们看到system在执行期间调用进程会一直等待shell命令执行完成(waitpid等待子进程结束)才返回,但是popen无须等待shell命令执行完成就返回了。我们可以理解system为串行执行,在执行期间调用进程放弃了”控制权”,popen为并行执行。

2.popen中的子进程没人给它”收尸”了啊?是的,如果你没有在调用popen后调用pclose那么这个子进程就可能变成”僵尸”。

3.对于管道已经很清楚,而管道写可能用的地方比较少。而对于写可能更常用的是system函数:

system("cat "Read pipe successfully!"
> test1")

4.如果不需要使用到程序的I/O数据流,那么system是最方便的。

而且system函数是C89和C99中标准定义的,可以跨平台使用。而popen是Posix 标准函数,可能在某些平台无法使用(windows应该是可以的吧,没做过测试)。

5.可以看出,popen可以控制程序的输入或者输出,而system的功能明显要弱一点,比如无法将读取结果用于程序中。

6.如果上述两个函数还无法满足你的交互需求,那么可以考虑exec函数组了。

system是用shell来调用程序=fork+exec+waitpid,而exec是直接让你的程序代替原来的程序运行。

system 是在单独的进程中执行命令,完了还会回到你的程序中。而exec函数是直接在你的进程中执行新的程序,新的程序会把你的程序覆盖,除非调用出错,否则你再也回不到exec后面的代码,就是说你的程序就变成了exec调用的那个程序了。

最后说一下exit函数:

exit是一个库函数,exit(1)表示发生错误后退出程序,   exit(0)表示正常退出。

对你的程序来说,没有区别。对使用你的程序的人或者程序来说,区别可就大了。

一般来说,exit 0 可以告知你的程序的使用者:你的程序是正常结束的。如果 exit 非 0 值,那么你的程序的使用者通常会认为你的程序产生了一个错误。

以 shell 为例,在 shell 中调用完你的程序之后,用 echo $? 命令就可以看到你的程序的 exit 值。在 shell 脚

本中,通常会根据上一个命令的 $? 值来进行一些流程控制。

同样的情形出现在 C 语言的 exec 系列函数中。

例:

当你 exit 0 的时候,在调用环境 echo $? 就返回0,也就是说调用环境就认为你的这个程序执行正确

当你 exit 1 的时候,一般是出错定义这个1,也可以是其他数字,很多系统程序这个错误编号是有约定的含义的。

但不为0 就表示程序运行出错。 调用环境就可以根据这个返回值判断 你这个程序运行是否ok。搜索如果你用 脚本 a 调用 脚本b
,要在a中判断b是否正常返回,就是根据 exit 0 or 1 来识别。执行完b后, 判断 $? 就是返回值

Linux之执行命令操作20170330的更多相关文章

  1. Linux后台执行命令:&和nohup nohup和&后台运行,进程查看及终止

    nohup和&后台运行,进程查看及终止   阅读目录 nohup和&后台运行,进程查看及终止 1.nohup 2.& 3.nohup和&的区别 &:是指在后台运 ...

  2. linux中执行命令权限不够怎样处理

    在linux中执行命令权限不够就要增加权限,先看遇到的情况 查看权限情况 那就赋予权限 执行命令

  3. Android 开发进入Linux系统执行命令 2018-5-25 Fri.

    /** * 进入linux cmd执行命令 * * @param command * @return */ private boolean runRootCommand(String command) ...

  4. [转帖]Linux后端执行命令的方法

    Linux 后台执行命令的方法 http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=4241330&fromuid=212883 ...

  5. expect 交互 之shell执行命令操作

    shell 执行命令操作 /usr/bin/expect -c " proc jiaohu {} { send_user expect_start expect { password { s ...

  6. Shell脚本中实现切换用户并执行命令操作【转】

    第一种方法 cat test.sh #!/bin/bashsu - test <<EOFpwd;exit;EOF 执行结果图: 第二种方法 当然也可以用下面的命令来执行 复制代码代码如下: ...

  7. java使用ssh连接Linux并执行命令

     方式1:通过设置账号密码和链接地址 maven pom.xml配置: <dependency>         <groupId>com.jcraft</groupId ...

  8. php 执行计划任务方式之 linux crontab 执行命令

    一.crond简介 crond 是linux下用来周期性的执行某种任务或等待处理某些事件的一个守护进程,与windows下的计划任务类似,当安装完成操作系统后,默认会安装此服务 工具,并且会自动启动c ...

  9. 初学Linux基本的命令操作应当记牢

    Linux管理文件和目录的命令 命令 功能 命令 功能 pwd 显示当前目录 ls 查看目录下的内容 cd 改变所在目录 cat 显示文件的内容 grep 在文件中查找某字符 cp 复制文件 touc ...

随机推荐

  1. 下载android sdk更新包离线安装解决方案

    本文转载自:http://xljboox.blog.163.com/blog/static/7628448320111159354738/ 第一次安装android sdk后进行开发包的更新,你应该了 ...

  2. emmmmmm

    211606342杨艺勇 211606379王熙航 单元测试 对每一个代码块进行测试,返回测试结果并和预期结果进行比对 对源代码进行相应的重构,以适应测试代码的调用,且不影响源代码的正常运行 通过与构 ...

  3. 在html中怎么格式化输出json字符串

    #今天的项目用到,看俊哥找到,特此记录下来 步骤: 1.在html页面中输入下面的标签,必须是在pre标签内输出格式才会生效: <pre id="songReqJson"&g ...

  4. c艹第三次作业

    1.git地址,不要介意仓库名. https://github.com/b666666666666666b/elevator-schedualing 2.首先,我先说一下我是怎么实现三个电梯的. 首先 ...

  5. 线段树---poj2528 Mayor’s posters【成段替换|离散化】

    poj2528 Mayor's posters 题意:在墙上贴海报,海报可以互相覆盖,问最后可以看见几张海报 思路:这题数据范围很大,直接搞超时+超内存,需要离散化: 离散化简单的来说就是只取我们需要 ...

  6. 欧拉函数phic以及超大数的快速幂

    题目:求a^b*c%mod; 其中b<=10^100000; 是不是很大..... /*当你要计算 A^B%C的时候 因为此题中的B很大,达到10^100000,所以我们应该联想到降幂公式. 降 ...

  7. PAT 甲级 1054 The Dominant Color

    https://pintia.cn/problem-sets/994805342720868352/problems/994805422639136768 Behind the scenes in t ...

  8. eclipse中jsp页面Invalid location of tag 解决办法分析小结

    在jsp页面使用标签过程中有时候不注意规则的话,eclipse会提示一些错误,下面针对这些错误提出相应的解决办法: <form></form>标签 1. Invalid loc ...

  9. egret 开发总结

    用egret快两年了,开发过两款成功的游戏.<<妖怪修走 |诸神的黄昏>><<损友圈|我的地盘>> 妖怪修走是个重度游戏,付费率超高.也比较成功. 损友 ...

  10. PHP中与类有关的运算符

    与类有关的运算符: new, instanceof:判断一个“变量”(对象,数据),是否是某个类的“实例”: 示意如下: class  A {} class  B {} class  C extend ...