Linux下的C编程有以下几种方法可以执行shell命令
- system()函数
- exec函数簇
- popen()函数
如果还需要获取返回结果,有两种较简单方便的方法
- popen()函数
- 匿名管道
1.system()函数
所需头文件:#include<stdlib.h>
函数原型:int system(const char *cmdstring);
cmdstring是一个字符指针,就是一个包含需要运行的shell命令的字符串
通过查阅《UNIX环境高级编程》,以下是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 != EINTR)
-
{
-
status =
-1;
-
break;
-
}
-
}
-
}
-
return(status);
-
}
返回值:
- 如果cmdstring字符指针为NULL,返回1
- 如果fork失败或者waitpid返回除EINTR之外的错,则返回-1
- 如果exec失败,即不能执行shell(多半是没这个命令),返回值如同shell执行了exit(127)一样,结果为32512
- 如果fork、exec、waitpid都没有问题,shell也有这个命令,那么返回值是shell的终止状态(即执行shell命令的返回值)
注:exec失败或者shell命令执行失败,返回值会填入返回的整形状态status的8~15位,0~7位全为0,所以exit(127)的结果为32512是将127换成二进制为1111111,填入status的8~15位,则为111111100000000,换成十进制就是32512
通过以下对程序的试验,个人得出结论,命令正确执行返回0,不太肯定所有的命令,尝试了mv,cp,touch,ls命令正确返回都为0;exec执行失败,多半是没这个命令,返回32512;如果是其他正整数,代表shell命令是有的,但shell命令执行出问题,例如下图ls一个没有的文件,返回512.
-
#include<stdio.h>
-
int main()
-
{
-
int ret =
0;
-
ret = system(
NULL);
-
printf(
"ret = %d \n",ret);
//ret = 1
-
return
0;
-
}
-
-
#include<stdio.h>
-
int main()
-
{
-
int ret =
0;
-
ret = system(
"exit 55");
-
printf(
"ret = %d \n",ret);
//ret = 14080
-
return
0;
-
}
-
-
#include<stdio.h>
-
int main()
-
{
-
int ret =
0;
-
ret = system(
"ls dsfgsdfg");
//ls一个没有的文件 ret = 512
-
printf(
"ret = %d \n",ret);
-
return
0;
-
}
-
-
#include<stdio.h>
-
int main()
-
{
-
int ret =
0;
-
ret = system(
"asdfgdsgs");
//输入一个没有的命令 ret = 32512
-
printf(
"ret = %d \n",ret);
-
return
0;
-
}
-
-
#include<stdio.h>
-
int main()
-
{
-
int ret =
0;
-
ret = system(
"ls");
-
printf(
"ret = %d \n",ret);
//正常 ret = 0
-
return
0;
-
}
2.exec函数簇
我就直接照搬我的文章《linux编程进程与线程基本实例》里的exec函数簇介绍了。
调用exec函数时,该调用ecec的进程执行的程序完全替换为新程序,但并不创建新进程,前后进程的ID并不改变。exec只是用磁盘上的一个新程序替换了当前进程的正文段、数据段、堆段和栈段。
-
#include <unistd.h>
-
extern
char **environ;
-
int execl(const char *path, const char *arg, ...);
-
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[]);
-
int execlp(const char *file, const char *arg, ...);
-
int execle(const char *path, const char *arg, ..., char * const envp[]);
最后一个参数为NULL 或者(char *)0
成功不会返回任何值,调用失败会返回-1
const char *path要写绝对路径,const char *file就不用
例如execlp("ls","ls","-l",NULL);
execl("/bin/ls","ls","-l",NULL);
char *arg[] = {"ls", "-a", NULL}
execv( "/bin/ls",arg);
execvp( "ls",arg);
3.popen()函数和pclose()函数
常见操作是创建一个连接到另一个进程(shell的命令行)的管道,然后读其输出或向其输入端发送数据。
工作原理:popen先执行fork,然后调用exec执行cmdstring,并返回一个标准的I/O文件指针。
头文件:#include<stdio.h>
原型:FILE *popen(const char *cmdstring, const char *type)
cmdstring:包含shell命令字符串
type:为”r”时,则文件指针连接到cmdstring的标准输出,也就是代表指向执行shell命令返回的消息,也可以认为链接到stdout
为”w”时,则文件指针连接到cmdstring的标准输入,也可以认为链接到stdin
int pclose(FILE *fp);
fp:为ponen返回的文件指针
返回值:成功返回cmdstring的终止状态;出错返回-1
下面是执行通过popen函数执行shell命令ls的代码
-
#include<stdio.h>
-
int main()
-
{
-
FILE *fp =
NULL;
-
char data[
100] = {
'0'};
-
fp = popen(
"ls",
"r");
-
if (fp ==
NULL)
-
{
-
printf(
"popen error!\n");
-
return
1;
-
}
-
while (fgets(data,
sizeof(data), fp) !=
NULL)
-
{
-
printf(
"%s", data);
-
}
-
pclose(fp);
-
return
0;
-
}
4.匿名管道pipe
使用管道来获取执行shell命令返回的信息,一般流程如下
1.创建管道
2.使用dup函数复制描述符将shell命令行标准输出绑定到管道的写端
3.从管道的读端读取数据
pipe函数
所需头文件:#include<unistd.h>
函数原型:int pipe(int fd[2]);
返回值:成功返回0,出错返回-1
一个例子:创建进程,创建匿名管道,子进程使用dup2函数将标准输出的描述符复制给管道的写端,父进程从管道的读端读取数据
-
#include<stdio.h>
-
#include<unistd.h>
-
#include<string.h>
-
#include<stdlib.h>
-
int main()
-
{
-
int fpipe[
2] = {
0};
-
pid_t fpid;
-
char massage[
1000] = {
0};
-
memset(massage,
0,
20);
-
if (pipe(fpipe) <
0)
-
{
-
printf(
"Create pipe error!\n");
-
}
-
fpid = fork();
-
if (fpid ==
0)
-
{
-
close(fpipe[
0]);
-
dup2(fpipe[
1],STDOUT_FILENO);
-
system(
"ls");
-
}
-
else
if (fpid >
0)
-
{
-
wait(
NULL);
-
printf(
"this is father,recieve:");
-
fflush(
stdout);
-
close(fpipe[
1]);
-
read(fpipe[
0], massage,
1000);
-
printf(
"%s\n",massage);
-
}
-
else
-
{
-
printf(
"create fork error!\n");
-
}
-
return
0;
-
}