从Linux程序中执行shell(程序、脚本)并获得输出结果


Contents

 

1. 

前言

 

 

2. 

使用临时文件

 

 

3. 

使用匿名管道

 

 

4. 

使用

popen 

 

5. 

小结

 

1. 

前言

 

Unix

界有一句名言:

一行

shell

脚本胜过万行

C

程序

,虽然这句话有些夸张,但不可否认的是,借助脚

本确实能够极大的简化一些编程工作。比如实现一个

ping

程序来测试网络的连通性,实现

ping

函数需要

写上

200~300

行代码,为什么不能直接调用系统的

ping

命令呢?通常在程序中通过

 

system

函数来调用

shell

命令。但是,

system

函数仅返回命令是否执行成功,而我们可能需要获得

shell

命令在控制台上输出

的结果。例如,执行外部命令

ping

后,如果执行失败,我们希望得到

ping

的返回信息。

 

2. 

使用临时文件

 

首先想到的方法就是将命令输出重定向到一个临时文件,在我们的应用程序中读取这个临时文件,获得外

部命令执行结果,代码如下所示:

 

#define CMD_STR_LEN 1024 

int mysystem(char* cmdstring, char* tmpfile) 

char cmd_string[CMD_STR_LEN]; 

tmpnam(tmpfile); 

sprintf(cmd_string, "%s > %s", cmdstring, tmpfile); 

return system(cmd_string); 

这种使用使用了临时文件作为应用程序和外部命令之间的联系桥梁,在应用程序中需要读取文件,然后再

删除该临时文件,比较繁琐,优点是实现简单,容易理解。有没有不借助临时文件的方法呢?

 

3. 

使用匿名管道

 

<>

一书中给出了一种通过匿名管道方式将程序结果输出到分页程序的例子,因此想到,我们也可以通过

管道来将外部命令的结果同应用程序连接起来。方法就是

fork

一个子进程,并创建一个匿名管道,在子进

程中执行

shell

命令,并将其标准输出

dup 

到匿名管道的输入端,父进程从管道中读取,即可获得

shell

命令的输出,代码如下:

 

 

int mysystem(char* cmdstring, char* buf, int len) 

int fd[2]; 

pid_t pid; 

int n, count;  

memset(buf, 0, len); 

if (pipe(fd) < 0) 

return -1; 

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

return -1; 

else if (pid > 0)  

close(fd[1]);  

count = 0; 

while ((n = read(fd[0], buf + count, len)) > 0 && count > len) 

count += n; 

close(fd[0]); 

if (waitpid(pid, NULL, 0) > 0) 

return -1; 

else  

close(fd[0]);  

if (fd[1] != STDOUT_FILENO) 

if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) 

return -1; 

close(fd[1]); 

}  

if (execl("/bin/sh", "sh", "-c", cmdstring, (char*)0) == -1) 

return -1; 

}  

return 0; 

4. 

使用

popen 

在学习

unix

编程的过程中,发现系统还提供了一个

popen

函数,可以非常简单的处理调用

shell

,其函数

原型如下:

 

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

该函数的作用是创建一个管道,

fork

一个进程,然后执行

shell

,而

shell

的输出可以采用读取文件的方式

获得。采用这种方法,既避免了创建临时文件,又不受输出字符数的限制,推荐使用。

 

popen

使用

FIFO

管道执行外部程序。

 

 

#include 

 

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

 

int pclose(FILE *stream); 

 

popen 

通过

type

r

还是

w

确定

command

的输入

/

输出方向,

r

w

是相对

command

的管道而言的。

r

表示

command

从管道中读入,

w

表示

 

command

通过管道输出到它的

stdout

popen

返回

FIFO

管道的

文件流指针。

pclose

则用于使用结束后关闭这个指针。

 

 

下面看一个例子:

 

 

#include 

 

#include 

 

#include 

 

#include 

 

#include 

 

int main( void ) 

 

 

FILE *stream; 

 

FILE *wstream; 

 

char buf[1024]; 

 

memset( buf, '/0', sizeof(buf) );//

初始化

buf,

以免后面写如乱码到文件中

 

 

stream = popen( "ls -l", "r" ); //

“ls 

l”

命令的输出

 

通过管道读取(

“r”

参数)到

FILE* stream 

 

wstream = fopen( "test_popen.txt", "w+"); //

新建一个可写的文件

 

 

fread( buf, sizeof(char), sizeof(buf), stream); //

将刚刚

FILE* stream

的数据流读取到

buf

 

 

fwrite( buf, 1, sizeof(buf), wstream );//

buf

中的数据写到

FILE *wstream

对应的流中,也是写到文件中

 

 

pclose( stream ); 

 

fclose( wstream ); 

 

return 0; 

 

 

[root@localhost src]# gcc popen.c 

 

[root@localhost src]# ./a.out 

 

[root@localhost src]# cat test_popen.txt 

 

总计

 

128 

 

-rwxr-xr-x 1 root root 5558 09-30 11:51 a.out 

 

-rwxr-xr-x 1 root root 542 09-30 00:00 child_fork.c 

 

-rwxr-xr-x 1 root root 480 09-30 00:13 execve.c 

 

-rwxr-xr-x 1 root root 1811 09-29 21:33 fork.c 

 

-rwxr-xr-x 1 root root 162 09-29 18:54 getpid.c 

 

-rwxr-xr-x 1 root root 1105 09-30 11:49 popen.c 

 

-rwxr-xr-x 1 root root 443 09-30 00:55 system.c 

 

-rwxr-xr-x 1 root root 0 09-30 11:51 test_popen.txt 

 

-rwxr-xr-x 1 root root 4094 09-30 11:39 test.txt 

5. 

小结

 

有统计数据表明,代码的缺陷率是一定的,与所使用的语言无关。

Linux

提供了很多的实用工具和脚本,在

程序中调用工具和脚本,无疑可以简化程序,从而降低代码的缺陷数目。

Linux shell

脚本也是一个强大的

工具,我们可以根据需要编制脚本,然后在程序中调用自定义脚本。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值