1 system介绍
在Unix系统中,system总是可用的。system接口如下:
#include <stdlib.h>
int system(const char* cmdstring);
system在其实现中调用了fork,exec和waitpid函数,因此有3种返回值:
(1)如果fork失败或waitpid返回除EINTR之外的出错,则system返回-1,且设置errno以指示错误类型。
(2)如果exec失败,则其返回值如同shell执行了exit(127)。
(3)如果fork,exec和waitpid都成功,则system的返回值是shell的终止状态。
2 使用system函数执行命令
如下的程序是system函数的一种实现。这个版本的system对信号没有进行处理。
#include <sys/wait.h>
#include <errno.h>
#include <unistd.h>
int system(const char *cmdstring) /* version without signal handling */
{
pid_t pid;
int status;
if (cmdstring == NULL)
return(1); /* always a command processor with UNIX */
if ((pid = fork()) < 0) {
status = -1; /* probably out of processes */
} else if (pid == 0) { /* child */
execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
_exit(127); /* execl error */
} else { /* parent */
while (waitpid(pid, &status, 0) < 0) {
if (errno != EINTR) {
status = -1; /* error other than EINTR from waitpid() */
break;
}
}
}
return(status);
}
子进程会调用execl起一个新程序(/bin/sh)去执行命令,若execl正常退出,system的返回值是shell的终止状态;若execl异常,则子进程执行_exit(127)。
主进程等待子进程退出。
注意:子进程退出调用_exit而不是exit。这是为了防止任一标准I/O缓冲在子进程中被冲洗(这些缓冲会在fork中由父进程复制到子进程)。
用如下程序对system函数进程测试:
#include <stdlib.h>
#include <sys/wait.h>
#include <stdio.h>
void pr_exit(int status)
{
if (WIFEXITED(status))
printf("normal termination, exit status = %d\n",
WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("abnormal termination, signal number = %d%s\n",
WTERMSIG(status),
#ifdef WCOREDUMP
WCOREDUMP(status) ? " (core file generated)" : "");
#else
"");
#endif
else if (WIFSTOPPED(status))
printf("child stopped, signal number = %d\n",
WSTOPSIG(status));
}
int main(void)
{
int status;
if ((status = system("date")) < 0)
printf("system() error");
pr_exit(status);
if ((status = system("nosuchcommand")) < 0)
printf("system() error");
pr_exit(status);
if ((status = system("who; exit 44")) < 0)
printf("system() error");
pr_exit(status);
exit(0);
}
输出:
2022年 05月 01日 星期日 21:08:15 CST
normal termination, exit status = 0
sh: 1: nosuchcommand: not found
normal termination, exit status = 127
xxx tty7 2022-05-02 05:00 (:0)
yyy tty8 2022-05-01 21:01 (:1)
normal termination, exit status = 44