从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 )
linux循环执行命令脚本{
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( "", "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
总计 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
-rwxr-xr-x 1 root root 4094 09-30 11:
5. ⼩结
有统计数据表明,代码的缺陷率是⼀定的,与所使⽤的语⾔⽆关。Linux提供了很多的实⽤⼯具和脚本,
在程序中调⽤⼯具和脚本,⽆疑可以简化程序,从⽽降低代码的缺陷数⽬。Linux shell脚本也是⼀个强⼤的⼯具,我们可以根据需要编制脚本,然后在程序中调⽤⾃定义脚本。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论