理论
我们先看下man手册是怎么说的man system
RETURN VALUE
The value returned is -1 on error (e.g., fork(2) failed), and the return status of the command otherwise. This latter return status is in the format speci‐
fied in wait(2). Thus, the exit code of the command will be WEXITSTATUS(status). In case /bin/sh could not be executed, the exit status will be that of a
command that does exit(127).
If the value of command is NULL, system() returns nonzero if the shell is available, and zero if not.
system() does not affect the wait status of any other children.
机翻一下
返回值
错误时返回的值为-1(例如,fork(2)failed),否则返回命令的状态。后一个返回状态采用wait(2)中指定的格式。因此,命令的退出代码将是WEXITSTATUS(status)。在无法执行/bin/sh的情况下,退出状态将是退出(127)的命令的状态。
如果command的值为空,如果shell可用,system()将返回非零,如果不可用,则返回零。
system()不影响任何其他子项的等待状态。
参考:System函数返回值 和popen system是个综合的操作,分解开来看就是相当于执行了
1 fork 生成一个子进程。
2 在子进程执行 execl("/bin/sh",“sh”,"-c" command,(char*)0);
3 waitpid
返回值:
1 如果fork失败了,或者waitpid返回除了EINTR之外的错误,system返回 -1;
2 execl执行失败,其返回值如同shell执行了"exit(127)" 一样。
3 如果上述三步都执行成功,那么,system返回值是shell的终止状态。
如果/bin/sh拉起shell命令失败,或者是shell命令没有正常执行 (比如命令根本就是非法的命令),那么,将原因填入status的8~15位。
一般错误来说
status = 256 * 信号编码
WEXITSTATUS(status) = 128 + 信号编号。
实测
下面给出一个程序。system函数传入一串乱七八糟的字符,我们看下结果
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/types.h>
int main(void)
{
pid_t status = system("wrqwqwd");
if (-1 == status)
{
printf("返回-1,fork失败了,或者waitpid返回除了EINTR之外的错误\n");
return 0;
}
else
{
printf("exit status value = [0x%x]\n", status);
if (WIFEXITED(status))
{
if (0 == WEXITSTATUS(status))
{
printf("0 == WEXITSTATUS(status),运行完毕\n");
}
else
{
printf("0 != WEXITSTATUS(status),script exit code: %d\n", WEXITSTATUS(status));
return 0;
}
}
else
{
printf("WIFEXITED(status)为假,exit status = [%d]\n", WEXITSTATUS(status));
return 0;
}
}
return 0;
}
16进制 7f00 转 10进制 为 32515。WEXITSTATUS(status)为127
如果execl执行失败,也即command没有顺利执行,比如被信号中断,或者command命令根本不存在,system()函数返回127.
我们传入 ls 试试
pid_t status = system("ls");
status 为 0,WEXITSTATUS(status)为0
执行成功,exit 0
我们执行下没有执行权限的shell脚本
pid_t status = system("./start.sh");
WEXITSTATUS(status)为126
shell脚本没有执行权限。
我们执行下有执行权限但是错误的shell脚本
start.sh
while :
do
#echo 1
done
status为 ox200 即 512,WEXITSTATUS(status)为 2.
具体原因参考:System函数返回值 和popen
我们可以看到,直接在终端执行sleep 7,然后用Ctrl+C发送SIGINT信号,异常退出,shell返回值为130,130的原因,
APUE上解释了,因为SIGINT 等于2,终止状态是128+信号编号,所以为130.
按照APUE上,我们的system调用应该将SIGINT忽略掉,然后正常返回,同时返回值为130,但是实际上LINUX下并不是这样
的。实际上system的返回值为2,并且异常退出了。
我们执行下有执行权限但是死循环的shell脚本
start.sh
while true
do
echo 1;
done
同样是死循环,然后我按了ctrl+C,发送 SIGINT信号。status为2
当我们运行死循环的shell脚本,然后kill 它
kill -9,status为9
同理,测试
命令kill -l
常见的信号
简单来说
system 返回值,调用函数后的返回值
shell 返回值,指脚本执行后的返回值
阶段1:创建子进程等准备工作。如果失败,返回-1
阶段2:调用/bin/sh拉起脚本,如果拉起失败或者shell未正常执行,原因值被写入ret中
阶段3:如果shell脚本执行成功,shell脚本的返回值写入ret中
WIFEXITED 用来判断阶段二的返回值
WEXITSTATUS 用来判断阶段三的返回值
判断一个脚本是否执行成功,应该满足三个条件:
-1 != ret
WIFEXITED(ret)为真
0 == WEXITSTATUS(ret)
注意:当shell脚本不存在时、没有执行条件等,前两个条件也会成立,此时WEXITSTATUS(ret)为127,所以shell脚本中不能将127作为返回值,shell脚本中的异常返回值最好从1开始递增,成功返回0。
一般错误来说
status = 256 * 信号编码
WEXITSTATUS(status) = 128 + 信号编号。
参考文章
Linux信号列表System函数返回值 和popenLinux system 函数
补充说明
man system
SYSTEM(3) Linux Programmer's Manual SYSTEM(3)
NAME
system - execute a shell command
SYNOPSIS
#include <stdlib.h>
int system(const char *command);
DESCRIPTION
system() executes a command specified in command by calling /bin/sh -c
command, and returns after the command has been completed. During exe‐
cution of the command, SIGCHLD will be blocked, and SIGINT and SIGQUIT
will be ignored.
RETURN VALUE
The value returned is -1 on error (e.g., fork(2) failed), and the
return status of the command otherwise. This latter return status is
in the format specified in wait(2). Thus, the exit code of the command
will be WEXITSTATUS(status). In case /bin/sh could not be executed,
the exit status will be that of a command that does exit(127).
If the value of command is NULL, system() returns nonzero if the shell
is available, and zero if not.
system() does not affect the wait status of any other children.
ATTRIBUTES
For an explanation of the terms used in this section, see
attributes(7).
┌──────────┬───────────────┬─────────┐
│Interface │ Attribute │ Value │
├──────────┼───────────────┼─────────┤
│system() │ Thread safety │ MT-Safe │
└──────────┴───────────────┴─────────┘
CONFORMING TO
C89, C99, POSIX.1-2001.
NOTES
If the _XOPEN_SOURCE feature test macro is defined (before including
any header files), then the macros described in wait(2) (WEXITSTATUS(),
etc.) are made available when including <stdlib.h>.
As mentioned, system() ignores SIGINT and SIGQUIT. This may make pro‐
grams that call it from a loop uninterruptible, unless they take care
themselves to check the exit status of the child. E.g.
while (something) {
int ret = system("foo");
if (WIFSIGNALED(ret) &&
(WTERMSIG(ret) == SIGINT || WTERMSIG(ret) == SIGQUIT))
break;
}
Do not use system() from a program with set-user-ID or set-group-ID
privileges, because strange values for some environment variables might
be used to subvert system integrity. Use the exec(3) family of func‐
tions instead, but not execlp(3) or execvp(3). system() will not, in
fact, work properly from programs with set-user-ID or set-group-ID
privileges on systems on which /bin/sh is bash version 2, since bash 2
drops privileges on startup. (Debian uses a modified bash which does
not do this when invoked as sh.)
In versions of glibc before 2.1.3, the check for the availability of
/bin/sh was not actually performed if command was NULL; instead it was
always assumed to be available, and system() always returned 1 in this
case. Since glibc 2.1.3, this check is performed because, even though
POSIX.1-2001 requires a conforming implementation to provide a shell,
that shell may not be available or executable if the calling program
has previously called chroot(2) (which is not specified by
POSIX.1-2001).
It is possible for the shell command to return 127, so that code is not
a sure indication that the execve(2) call failed.
SEE ALSO
sh(1), signal(2), wait(2), exec(3)
COLOPHON
This page is part of release 3.53 of the Linux man-pages project. A
description of the project, and information about reporting bugs, can
be found at http://www.kernel.org/doc/man-pages/.
2010-09-10 SYSTEM(3)