建站一条龙,网站图片设计效果图,广东省建设厅网站6,珠海市做网站文章目录 摘要前言exec函数的使用system函数使用popen函数的使用 摘要
本文尝试使用exec,system,popen函数#xff0c;来执行一个shell命令。(1) 如果只需要执行命令后的返回值#xff0c;不关心标准输出#xff0c;错误输出#xff0c;可以使用system函数。(2) 如果希望拿… 文章目录 摘要前言exec函数的使用system函数使用popen函数的使用 摘要
本文尝试使用exec,system,popen函数来执行一个shell命令。(1) 如果只需要执行命令后的返回值不关心标准输出错误输出可以使用system函数。(2) 如果希望拿到返回值标准输出可以使用popen。(2) 如果前面两个函数都不能满足要求那使用exec虽然这个比较麻烦。 前言
老实说(To be honest), 在Linux c 中调用exec/system/popen来执行shell命令都不太完美。exec的缺点是用起来比较麻烦。system和popen是封装的还不够好。
谈论好/坏之前需要建立评价标准。或者说需要实现哪些功能才算好了。我们参考下Boost.Process,一个C进程库有哪些功能。
创建一个子进程。为子进程设置输入/输出流(为子进程设置输入流读取子进程的标准输出/错误输出)(同步和异步)。等待进程结束,获取返回码(同步和异步)。终止子进程。
system函数只能拿到返回值; popen只能设置标准输入或者标准输出没法单独获取到错误输出。而想要使用exec函数优雅又安全的实现上面功能不容易挺不容易。
哎呀凑活着用就是嘞像生活一样。 exec函数的使用
参考: exec(3) - Linux manual page , 《unix环境高级编程》8.10 函数exec
这个函数不太好写我也不咋喜欢用因为有些麻烦。我们看下面这个示例。
#include stdio.h
#include stdlib.h
#include sys/wait.h
#include syslog.h
#include unistd.hint main(int argc, char *argv[]) {openlog(exec, LOG_PERROR, 0);char *cmd ls;char *ls_argv[] {ls, -alh, NO_EXIST_FILE, NULL};pid_t pid;if ((pid fork()) 0) {syslog(LOG_ERR, fork error);} else if (pid 0) { /* specify pathname, specify environment */if (execvp(cmd, ls_argv) 0) {syslog(LOG_ERR, execvp error);}}int status;if (waitpid(pid, status, 0) 0) {syslog(LOG_ERR, wait error);} else {if (WIFEXITED(status)) {int ret WEXITSTATUS(status);syslog(LOG_INFO, subprocess return code: %d, ret);}}exit(0);
}这个程序很简单创建一个子进程并执行shell命令。父进程等待子进程结束。
仔细推敲的话上面的实现是有问题的。
(1) fork() 执行失败的时候会返回-1。而waitpid(3) - Linux man page的第一个参数是-1时表示等待任意一个子进程而不是我们目前希望的子进程。如果此时没有自进程它会立即出错返回。 (2) 上面我们希望拿到子进程执行后的返回码。但是如果程序不是正常(return,exit方式)结束比如信号终止或者coredump是拿不到子进程本身的返回值的。 system函数使用
参考system(3) - Linux manual page , 《unix环境高级编程》8.13 函数system
system函数的行为像是使用fork创建子进程然后像下面这个调用exec函数。
execl(/bin/sh, sh, -c, command, (char *) NULL);父进程在执行命令的期间会阻塞SIGCHLD信号忽略SIGINT和SIGQUIT信号。
我挺喜欢system函数。因为它的接口简单易上手。下面我们使用system函数重写下上面的程序。
#include errno.h
#include stdio.h
#include stdlib.h
#include string.h
#include syslog.h
#include unistd.hint main(int argc, char *argv[]) {openlog(system, LOG_PERROR, 0);char *cmd ls -alh NO_EXIST_FILE;int status system(cmd);if (status -1) {syslog(LOG_ERR, create subprocess failed: %s, strerror(errno));goto err;}if (WIFEXITED(status)) {int ret WEXITSTATUS(status);syslog(LOG_INFO, subprocess return code: %d, ret);}err:exit(0);
}可惜的是拿不到标准错误输出。这个错误输出直接输出到命令行了不方便写入日志。
输出如下。
ls: cannot access NO_EXIST_FILE: No such file or directory
system: subprocess return code: 2popen函数的使用
程序员这个行业某些时候真是太无聊了必须得花时间在“茴香豆的茴有哪些写法”上。
我们再看看看popen的使用。
参考: popen(3) - Linux manual page , 《unix环境高级编程》15.3 函数popen和pclose
我们继续使用popen实现上面代码的功能。(红烧鱼清蒸鱼糖醋鲤鱼一多吃)
#include errno.h
#include stdio.h
#include stdlib.h
#include string.h
#include sys/wait.h
#include syslog.h
#include unistd.hint main(int argc, char *argv[]) {openlog(system, LOG_PERROR, 0);char *cmd ls -alh NO_EXIST_FILE 21;// char *cmd ls -alh NO_EXIST_FILE;FILE *fp popen(cmd, r);if (fp NULL) {syslog(LOG_ERR, create subprocess failed: %s, strerror(errno));exit(0);}char line[1024];while (fgets(line, sizeof(line), fp) ! NULL) {printf(header: %s, line);}int status pclose(fp);if (status -1) {syslog(LOG_ERR, pclose failed: %s, strerror(errno));} else if (WIFEXITED(status)) {int ret WEXITSTATUS(status);syslog(LOG_INFO, subprocess return code: %d, ret);}exit(0);
}关于popen接口的使用自行参考官方文档。下面看两个更有意思的问题。
问题一能否单独获取标准错误输出而不是将标准错误输出混在标准输出中。
答案是可以但不是一个好主意得引入select这样的函数来保证可以同时读取两个流。可以参考: c popen won’t catch stderr - Stack Overflow