最近工作中在Linux
下,某些指定的程序需要调用指定的shell脚本完成指定工作,以前也曾经做过类似的功能,调用system
函数执行指定的脚本,以前并不关心shell脚本是否执行成功了,现在的功能需要根据shell脚本执行成功与否,于是查询了下system
函数的说明,有此文以做笔记之用。
system 函数说明
#include <stdlib.h>
int system(const char *command);
功能:调用/bin/sh -c 执行指定的脚本 command
常规使用方法:
int ret = system("./test.sh");
关于返回值:
-
system
返回值,调用函数后的返回值 -
shell
返回值,指脚本执行后的返回值
如何判断脚本是否执行成功
- ret == 0
- ret != -1
以上两个对于返回值的判定,是经常被使用的,但是正确么。。。
答案是都错
system 返回值说明
man手册
The value returned is -1 on error (e.g. fork() 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 non-zero if the shell is available, and zero if not.system() does not affect the wait status of any other children.
看着挺晕的,但是如果对于system
的执行过程了解的话,就很容易理解了,函数执行分为以下几个阶段。
阶段1:创建子进程等准备工作。如果失败,返回-1
阶段2:调用/bin/sh
拉起脚本,如果拉起失败或者shell未正常执行,原因值被写入ret中
阶段3:如果shell
脚本执行成功,shell
脚本的返回值写入ret中
从上面可知,不管shell
脚本返回什么值,只要调用了/bin/sh,并且执行过程没有被信号中断,都算正常结束。因为脚本是在子进程中执行的,所以要想获取脚本是否执行成功的方法只能用系统提供的两个宏。
WIFEXITED
用来判断阶段二的返回值
WEXITSTATUS
用来判断阶段三的返回值
由于我们一般在shell
中会通过返回值判断脚本是否执行成功,成功返回0,成功返回整数。所以判断一个脚本是否执行成功,应该满足三个条件:
- -1 != ret
- WIFEXITED(ret)为真
- 0 == WEXITSTATUS(ret)
注意:当shell
脚本不存在时、没有执行条件等,前两个条件也会成立,此时WEXITSTATUS(ret)为127,所以shell脚本中不能将127作为返回值,shell脚本中的异常返回值最好从1开始递增,成功返回0。
实例代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
pid_t status;
status = system("./test.sh");
if (-1 == status)
{
printf("system error!");
}
else
{
printf("exit status value = [0x%x]\n", status);
if (WIFEXITED(status))
{
if (0 == WEXITSTATUS(status))
{
printf("run shell script successfully.\n");
}
else
{
printf("run shell script fail, script exit code: %d\n", WEXITSTATUS(status));
}
}
else
{
printf("exit status = [%d]\n", WEXITSTATUS(status));
}
}
return 0;
}
总结
system
用起来,看则简单,实则不那么简单,有很多隐藏的坑,需要自己深入理解原理,才能更好地使用,也可以用其他实现方式完成相同的功能。
最后对自己说,多写,多思,多总结