linux执行命令并获取结果(system)
执行系统命令,并返回输出的结果
首先需要了解mkstemp():
mkstemp()函数在系统中以唯一的文件名创建一个文件并打开,而且只有当前用户才能访问这个临时文件,并进行读、写操作。
mkstemp函数在系统中以唯一的文件名创建一个文件并打开,而且只有当前用户才能访问这个临时文件,并进行读、写操作。 mkstemp函数只有一个参数,这个参数是个以“XXXXXX”结尾的非空字符串。mkstemp函数会用随机产生的字符串替换“XXXXXX”,保证 了文件名的唯一性。 函数返回一个文件描述符,如果执行失败返回-1。
在glibc 2.0.6 以及更早的glibc库中这个文件的访问权限是0666,glibc 2.0.7以后的库这个文件的访问权限是0600。
临时文件使用完成后应及时删除,否则临时文件目录会塞满垃圾。由于mkstemp函数创建的临时文件不能自动删除,所以执行完 mkstemp函数后要调用unlink函数,unlink函数删除文件的目录入口,但临时文件还可以通过文件描述符进行访问,直到最后一个打开的进程关 闭文件操作符,或者程序退出后临时文件被自动彻底地删除。
函数功能表示:读取命令执行结果,放到临时文件,并将结果读到buf中,删除临时文件
/** *@brief 执行系统命令,并返回输出的结果 *@param[in] cmdstring,命令串 *@param[in] buf,存放命令结果的缓冲区 *@param[in] size,缓冲区的大小 *@param[out] *@return 返回写入到buf中的字符串长度,不含\0 ; -1: 失败; *@remark *@version V1.0.0 *@note buf中最多返回size-1个字符,字符串始终以\0结尾。 */ int get_cmd_results(const char *cmdstring, char *buff, int size) { char cmd_string[200] = {0}; char tmpfile[100] = {0}; char tmp_buf[100] = {0}; int fd; int tmp_fd; int nbytes; memset(buff, 0, size); if((cmdstring == NULL) || (strlen(cmdstring) > (sizeof(tmpfile) + 8)) || ((strlen(cmdstring) + strlen(tmpfile) + 5) > sizeof(cmd_string))) { printf("cmd is too long or NULL!\n"); return -1; } sscanf(cmdstring, "%[a-Z]", tmp_buf);/*%[a-z] 表示匹配a到z中任意字符,贪婪性(尽可能多的匹配) */ sprintf(tmpfile, "/tmp/%s-XXXXXX", tmp_buf); tmp_fd = mkstemp(tmpfile); if(tmp_fd < 0) { printf("mkstemp failed\n"); return -1; } close(tmp_fd); sprintf(cmd_string, "%s > %s 2>&1", cmdstring, tmpfile);/*标准输出(1),标准错误(2)都输出到临时文件*/ if(system_ex(cmd_string, 20) < 0) { printf("run \"%s\" ret < 0!\n", cmd_string); } fd = open(tmpfile, O_RDONLY); if(fd < 0) { printf("open %s failed!\n", tmpfile); nbytes = -1; } else { nbytes = read(fd, buff, size - 1); close(fd); } memset(cmd_string, 0, sizeof(cmd_string)); sprintf(cmd_string, "rm -rf /tmp/%s-*", tmp_buf); system_ex(cmd_string, 20); return nbytes; }
system_ex:
首先请了解信号:signal和sigaction
https://blog.csdn.net/weibo1230123/article/details/81411827
https://www.cnblogs.com/lidabo/p/4581065.html
创建子进程执行命令,父进程忽略ignore SIGINT and SIGQUIT ,来避免影响子进程执行即需要子进程执行完毕,子进程不忽略信号,当超时或者子进程退出
则恢复信号状态,超时的话,还需要kill掉子进程等
//system函数扩展,加入超时值(0表示永久等待) //超时时返回-2,其他情况返回不变。 int system_ex(const char *cmdstring, unsigned int timeout) /* with appropriate signal handling */ { pid_t pid; int status; struct sigaction ignore, saveintr, savequit; sigset_t chldmask, savemask; //精度换成十分之一秒 timeout *= 10; if (timeout == 0) timeout = 0xFFFFFFFF; if (cmdstring == NULL) return(1); /* always a command processor with UNIX */ ignore.sa_handler = SIG_IGN; /* ignore SIGINT and SIGQUIT */ sigemptyset(&ignore.sa_mask); ignore.sa_flags = 0; if (sigaction(SIGINT, &ignore, &saveintr) < 0) return(-1); if (sigaction(SIGQUIT, &ignore, &savequit) < 0) return(-1); sigemptyset(&chldmask); /* now block SIGCHLD */ sigaddset(&chldmask, SIGCHLD); if (sigprocmask(SIG_BLOCK, &chldmask, &savemask) < 0) return(-1); if ((pid = fork()) < 0) { return -1; /* probably out of processes */ } else if (pid == 0) { /* child */ /* restore previous signal actions & reset signal mask */ sigaction(SIGINT, &saveintr, NULL); sigaction(SIGQUIT, &savequit, NULL); sigprocmask(SIG_SETMASK, &savemask, NULL); /*通常exec会放在fork() 函数的子进程部分, 来替代子进程执行啦, 执行成功后子程序就会消失, 但是执行失败的话, 必须用exit()函数来让子进程退出!*/ execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);/*exec函数会取代执行它的进程, 也就是说, 一旦exec函数执行成功, 它就不会返回了, 进程结束. 但是如果exec函数执行失败, 它会返回失败的信息, 而且进程继续执行后面的代码!*/ _exit(127); /* exec error */ } /* parent */ int ret = 0; while (timeout-- > 0 && (ret = waitpid(pid, &status, WNOHANG)) == 0) usleep(100*1000); /* restore previous signal actions & reset signal mask */ if (sigaction(SIGINT, &saveintr, NULL) < 0) return(-1); if (sigaction(SIGQUIT, &savequit, NULL) < 0) return(-1); if (sigprocmask(SIG_SETMASK, &savemask, NULL) < 0) return(-1); if (ret < 0) return -1; if (ret > 0) return status; kill(pid, SIGKILL); waitpid(pid, &status, 0); return -2; }