c/c++程序内部调用shell脚本
2019年01月08日 17:17:12 儿时凿壁偷光 阅读数:60
system()
函数原型:
#include <stdlib.h>
int system(const char *str)
#!/bin/sh
echo $HOME
#include <stdlib.h>
#include <iostream>
#include <string>
int main()
{
std::string res;
res = system("./test.sh");
std::cout << res << '\n';
return 0;
}
特点:
1.两种错误返回值:
-1 system()进行fork子进程失败;
127 执行脚本或shell命令失败
2.无法在程序中直接获取到shell命令的返回内容
popen()
函数原型:
#include <stdio.h>
FILE* popen(char *command,char *type)
- 1
- 2
脚本示例:
同上
#include <stdio.h> //popen()
#include <string.h> //memset()
int main()
{
FILE *fp;
char buffer[80];
memset(buffer, 0x00, sizeof(buffer));
fp = popen("./test.sh", "r");
fgets(buffer, sizeof(buffer), fp);
printf("[%s]\n", buffer);
pclose(fp);
return 0;
}
特点:
1. 用 创建管道 的 方式 启动 一个 进程, 并调用 shell
2. 可在程序内部获取shell执行后的返回内容
参考博客 :https://blog.youkuaiyun.com/luokehua789789/article/details/53117904
====================================================================================================================================================================================================================================================================================================================================================================
linux下如何用c语言调用shell命令
2016年04月02日 22:36:43 HeroKern 阅读数:15143更多
个人分类: C language
版权声明:欢迎关注公众号herok,定期推送高质量技术干货文章。 https://blog.youkuaiyun.com/qq_21792169/article/details/51045846
C程序调用shell脚本共有三种法子 :system()、popen()、exec系列数call_exec1.c ,
system() 不用你自己去产生进程,它已经封装了,直接加入自己的命令
exec 需要你自己 fork 进程,然后exec 自己的命令
popen() 也可以实现执行你的命令,比system 开销小
方法一、system()的使用,我直接上代码吧
int system(const char *command);
我在/home/book/shell新建一个test.sh文件如下:
-
<span style="font-size:18px;"><span style="font-size:18px;">#!bin/bash
-
echo $HOME
-
echo "the is test!"</span></span>
test.c文件如下:
-
<span style="font-size:18px;"><span style="font-size:18px;">#include<stdlib.h>
-
int main()
-
{
-
system("bash /home/book/shell/test.sh"); /* chmod +x test.sh ,路径前面要加上bash */
-
return 0;
-
}</span></span>
执行如下命令来编译:
-
<span style="font-size:18px;">gcc test.c -o test
-
</span>
测试命令:
<span style="font-size:18px;">./test</span>
结果如下:
-
<span style="font-size:18px;">/root
-
the is test!</span>
方法二:popen() 会调用fork()产生 子历程,然后从子历程中调用/bin/sh -c来履行 参数command的指令。参数type可应用 “r”代表读取,“w”代表写入。遵循此type值,popen()会建立 管道连到子历程的标准 输出设备 或标准 输入设备 ,然后返回一个文件指针。随后历程便可利用 此文件指针来读取子历程的输出设备 或是写入到子历程的标准 输入设备 中。此外,所有应用 文 件指针(FILE*)操作的函数也都可以应用 ,除了fclose()以外。
返回值:若成功 则返回文件指针,否则返回NULL,差错 原因存于errno中。注意:在编写具SUID/SGID权限的程序时请尽量避免应用 popen(),popen()会继承环境变量,通过环境变量可能会造成系统安全的问题
-
FILE *popen(const char *command, const char *type);
-
int pclose(FILE *stream);
其他不用改变我们直接修改test.c文件:
-
#include<stdio.h>
-
int main()
-
{
-
char buffer[80];
-
FILE *fp=popen("bash /home/book/shell/test.sh","r");
-
fgets(buffer,sizeof(buffer),fp);
-
printf("%s",buffer);
-
pclose(fp);
-
return 0;
-
}
方法三:exec函数簇 (我不太懂,copy别人的,也没有验证,习惯方法一)
需要注意的是exec并不是1个函数, 其实它只是一组函数的统称, 它包括下面6个函数:
-
#include <unistd.h>
-
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()函数来让子进程退出!
下面是各个例子:
2.1 execv 函数
[cpp] view plain copy
- 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 函数
[cpp] view plain copy
- if (fork() == 0){
- //child process
- char * execvp_str[] = {"echo", "executed by execvp",">>", "~/abc.txt",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 函数
[cpp] view plain copy
- 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 函数
[cpp] view plain copy
- 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 函数
[cpp] view plain copy
- 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 函数
[cpp] view plain copy
- 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");
- }