linux下c语⾔调⽤shell命令的⽅法:system、popen、exec系
列函数
1、system(执⾏shell 命令)
相关函数 fork,execve,waitpid,popen
表头⽂件 #include<stdlib.h>
定义函数 int system(const char * string);
函数说明 system()会调⽤fork()产⽣⼦进程,由⼦进程来调⽤/bin/sh-c string来执⾏参数string字符串所代表的命令,此命令执⾏完后随即返回原调⽤的进程。在调⽤system( )期间SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会被忽略。返回值 如果system() 在调⽤/bin/sh时失败则返回127,其他失败原因返回-1。若参数string为空指针(NULL),则返回⾮零值。如果system()调
⽤成功则最后会返回执⾏shell命令后的返回值,但是此返回值也有可能为system()调⽤/bin/sh失败所返回的127,因此最好能再检查errno 来确认执⾏成功。
附加说明 在编写具有SUID/SGID权限的程序时请勿使⽤system( ),system( )会继承环境变量,通过环境变量可能会造成系统安全的问题。
范例:
#include<stdlib.h>
main()
{
system(“ls -al /etc/passwd /etc/shadow”);
}
2、popen(建⽴管道I/O)
相关函数 pipe,mkfifo,pclose,fork,system,fopen
表头⽂件 #include<stdio.h>
定义函数 FILE * popen( const char * command,const char * type);
函数说明 popen()会调⽤fork()产⽣⼦进程,然后从⼦进程中调⽤/bin/sh -c来执⾏参数command的指令。参数type可使⽤“r”代表读取,“w”代表写⼊。依照此type值,popen()会建⽴管道连到⼦进程的标准输出设备或标准输⼊设备,然后返回⼀个⽂件指针。随后进程便可利⽤此⽂件指针来读取⼦进程的输出设备或是写⼊到⼦进程的标准输⼊设备中。此外,所有使⽤⽂件指针(FILE*)操作的函数也都可以使⽤,除了fclose()以外。返回值 若成功则返回⽂件指针,否则返回NULL,错误原因存于errno中。错误代码 EINVAL参数type不合法。
注意事项 在编写具SUID/SGID权限的程序时请尽量避免使⽤popen(),popen()会继承环境变量,通过环境变量可能会造成系统安全的问题。
范例:
#include<stdio.h>
main()
{
FILE * fp;
char buffer[80];
fp=popen(“cat /etc/passwd”,”r”);
fgets(buffer,sizeof(buffer),fp);
printf(“%s”,buffer);
pclose(fp);
}
3、linux exec的⽤法
需要注意的是exec并不是1个函数, 其实它只是⼀组函数的统称, 它包括下⾯6个函数:
#include <unistd.h>
shell命令属于什么语言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[]);
可以见到这6个函数名字不同, ⽽且他们⽤于接受的参数也不同。
实际上他们的功能都是差不多的, 因为要⽤于接受不同的参数所以要⽤不同的名字区分它们, 毕竟c语⾔没有函数重载的功能嘛
但是实际上它们的命名是有规律的:
exec[l or v][p][e]
exec函数⾥的参数可以分成3个部分, 执⾏⽂件部分, 命令参数部分, 环境变量部分。
例如我要执⾏1个命令  ls -l /home/gateman
执⾏⽂件部分 就是  "/usr/bin/ls"
命令参赛部分 就是 "ls","-l","/home/gateman",NULL 见到是以ls开头 每1个空格都必须分开成2个部分, ⽽且以NULL结尾的啊.
环境变量部分, 这是1个数组,最后的元素必须是NULL 例如char * env[] = {"PATH=/home/gateman", "USER=lei", "STATUS = testing",  NULL};
好了说下命名规则:
e后续,  参数必须带环境变量部分,  环境变零部分参数会成为执⾏exec函数期间的环境变量, ⽐较少⽤
l 后续,  命令参数部分必须以"," 相隔, 最后1个命令参数必须是NULL
v 后续,  命令参数部分必须是1个以NULL结尾的字符串指针数组的头部指针。例如char * pstr就是1个字符串的指针, char * pstr[]就是数组了, 分别指向各个字符串。
p后续,  执⾏⽂件部分可以不带路径, exec函数会在$PATH中
还有1个注意的是, exec函数会取代执⾏它的进程,  也就是说, ⼀旦exec函数执⾏成功, 它就不会返回了, 进程结束.  但是如果exec函数执⾏失败, 它会返回失败的信息,  ⽽且进程继续执⾏后⾯的代码!
通常exec会放在fork() 函数的⼦进程部分, 来替代⼦进程执⾏啦, 执⾏成功后⼦程序就会消失,  但是执⾏失败的话, 必须⽤exit()函数来让⼦进程退出!
下⾯是各个例⼦:
3.1  execv 函数
int childpid;
int i;
if (fork() == 0){
//child process
char * execv_str[] = {"echo", "executed by execv",NULL};
if (execv("/usr/bin/echo",execv_str) <0 ){
perror("error on exec");
exit(0);
}
}else{
//parent process
wait(&childpid);
printf("execv done\n\n");
}
注意字符串指针数组的定义和赋值
2.2  execvp 函数
if (fork() == 0){
//child process
char * execvp_str[] = {"echo", "executed by execvp",">>", "~/",NULL};          if (execvp("echo",execvp_str) <0 ){
perror("error on exec");
exit(0);
}
}else{
//parent process
wait(&childpid);
printf("execvp done\n\n");
}
2.3 execve 函数
if (fork() == 0){
//child process
char * execve_str[] = {"env",NULL};
char * env[] = {"PATH=/tmp", "USER=lei", "STATUS=testing", NULL};
if (execve("/usr/bin/env",execve_str,env) <0 ){
perror("error on exec");
exit(0);
}
}else{
//parent process
wait(&childpid);
printf("execve done\n\n");
}
2.4 execl 函数
if (fork() == 0){
//child process
if (execl("/usr/bin/echo","echo","executed by execl" ,NULL) <0 ){
perror("error on exec");
exit(0);
}
}else{
//parent process
wait(&childpid);
printf("execv done\n\n");
}
2.5 execlp 函数
if (fork() == 0){
//child process
if (execlp("echo","echo","executed by execlp" ,NULL) <0 ){
perror("error on exec");
exit(0);
}
}else{
//parent process
wait(&childpid);
printf("execlp done\n\n");
}
2.6 execle 函数
if (fork() == 0){
//child process
char * env[] = {"PATH=/home/gateman", "USER=lei", "STATUS=testing", NULL};          if (execle("/usr/bin/env","env",NULL,env) <0){
perror("error on exec");
exit(0);
}
}else{
//parent process
wait(&childpid);
printf("execle done\n\n");
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。