2008-12-26 47 views
5

我有几个独立的可执行Perl,PHP CLI脚本和C++程序,为此我需要开发一个退出错误代码策略。这些程序由其他程序使用我创建的用于在PHP中使用exec()的包装类调用。所以,我将能够得到一个错误代码。根据该错误代码,调用脚本需要做些事情。什么是一个好的Linux退出错误代码策略?

我已经做了一点研究,看起来像1-254(或者可能只是1-127)范围内的任何事情都可能是用户定义的错误代码的公平游戏。

我只是想知道其他人在这种情况下如何接近错误处理。

回答

8

唯一的约定是,你为成功返回0,而对于错误返回0以外的东西。大多数着名的unix程序记录了它们可以返回的各种返回代码,您也应该如此。尝试为任何任意程序可能返回的所有可能的错误代码创建一个通用列表并没有多大意义,否则,最终会出现tens of thousands of them like some other OS's,即使如此,它并不总是涵盖特定类型的您想要返回的错误。

因此,只要保持一致,并确保记录您决定使用的任何方案。

6

1-127是可用的范围。任何超过127的应该是“异常”退出 - 由信号终止。

当你在它的时候,考虑使用stdout而不是退出代码。退出代码是传统用来表示成功,失败,并可能是另一种状态。而不是使用退出代码,尝试使用stdout的方式expr和wc使用它。然后你可以在调用者中使用反引号或类似的东西来提取结果。

+2

使用错误消息的stderr。 – iny 2008-12-26 15:09:28

3

Unix的宣言状态 - 尽快

退出并大声地对错误

或类似的东西

2

不要试图编码太多的意义进入退出值:详细的状态和错误报告应该按照Arkadiy的建议转到stdout/stderr。

但是,我发现使用二进制数字对它们进行编码仅仅表示出口值中的少数状态非常有用。例如,假设您有以下做作含义:

0000 : 0 (no error) 
0001 : 1 (error) 
0010 : 2 (I/O error) 
0100 : 4 (user input error) 
1000 : 8 (permission error) 

然后,用户输入错误将有5(4 + 1)返回值,而日志文件没有写权限可能有一个返回值为11(8 + 2 + 1)。由于不同的含义是在返回值中独立编码的,因此可以通过检查哪些位被设置来轻松查看发生了什么。

作为特殊情况,看是否有错误,你可以和1

返回代码,通过这样做,你可以编码几个不同的东西,在返回代码,在一个明确的和简单的方法。我只用它来做出简单的决定,比如“应该重启进程”,“返回值和相关日志是否需要发送给管理员”等等。任何详细的诊断信息都应该记录到日志或stdout/stderr。

1

正常退出状态从0到255(请参阅Exit codes bigger than 255 posssible讨论原因)。通常,状态0表示成功;其他任何东西都是实现定义的错误。我知道一个通​​过退出状态报告DBMS服务器状态的程序;这是实现定义的退出状态的特例。请注意,您可以定义程序状态的实现。

我无法将它放入300个字符;否则这将是@ Arkadiy的答案的评论。

Arkadiy是正确的,在退出状态字的一部分中,除零以外的值表示终止进程的信号,第8位通常表示核心转储,但退出状态的该部分不同于主0..255状态。然而,当一个进程因信号而死亡时,外壳(无论它是哪个外壳)都会出现问题。有8位数据要显示16位数据,这总是很棘手。壳看起来要做的是取信号码并加128。因此,如果一个进程由于中断而停止(信号编号2,SIGINT),shell将退出状态报告为130.但是,内核将状态报告为0x0002; shell已经修改了内核报告的内容。

下面的C代码演示了这一点。有两个程序

  • suicide它会使用您选择的信号(默认为中断)来杀死它自己。
  • exitstatus它运行一个命令(如suicide)并报告内核退出状态。

这里的suicide.c

/* 
@(#)File:   $RCSfile: suicide.c,v $ 
@(#)Version:  $Revision: 1.2 $ 
@(#)Last changed: $Date: 2008/12/28 03:45:18 $ 
@(#)Purpose:  Commit suicide using kill() 
@(#)Author:   J Leffler 
@(#)Copyright:  (C) JLSS 2008 
@(#)Product:  :PRODUCT: 
*/ 

/*TABSTOP=4*/ 

#if __STDC_VERSION__ >= 199901L 
#define _XOPEN_SOURCE 600 
#else 
#define _XOPEN_SOURCE 500 
#endif /* __STDC_VERSION__ */ 

#include <signal.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include "stderr.h" 

static const char usestr[] = "[-V][-s signal]"; 

#ifndef lint 
/* Prevent over-aggressive optimizers from eliminating ID string */ 
extern const char jlss_id_suicide_c[]; 
const char jlss_id_suicide_c[] = "@(#)$Id: suicide.c,v 1.2 2008/12/28 03:45:18 jleffler Exp $"; 
#endif /* lint */ 

int main(int argc, char **argv) 
{ 
    int signum = SIGINT; 
    int opt; 
    char *end; 

    err_setarg0(argv[0]); 

    while ((opt = getopt(argc, argv, "Vs:")) != -1) 
    { 
     switch (opt) 
     { 
     case 's': 
      signum = strtol(optarg, &end, 0); 
      if (*end != '\0' || signum <= 0) 
       err_error("invalid signal number %s\n", optarg); 
      break; 
     case 'V': 
      err_version("SUICIDE", &"@(#)$Revision: 1.2 $ ($Date: 2008/12/28 03:45:18 $)"[4]); 
      break; 
     default: 
      err_usage(usestr); 
      break; 
     } 
    } 
    if (optind != argc) 
     err_usage(usestr); 
    kill(getpid(), signum); 
    return(0); 
} 

而这里的exitstatus.c

/* 
@(#)File:   $RCSfile: exitstatus.c,v $ 
@(#)Version:  $Revision: 1.2 $ 
@(#)Last changed: $Date: 2008/12/28 03:45:18 $ 
@(#)Purpose:  Run command and report 16-bit exit status 
@(#)Author:   J Leffler 
@(#)Copyright:  (C) JLSS 2008 
@(#)Product:  :PRODUCT: 
*/ 

/*TABSTOP=4*/ 

#if __STDC_VERSION__ >= 199901L 
#define _XOPEN_SOURCE 600 
#else 
#define _XOPEN_SOURCE 500 
#endif /* __STDC_VERSION__ */ 

#include <stdio.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
#include "stderr.h" 

#ifndef lint 
/* Prevent over-aggressive optimizers from eliminating ID string */ 
extern const char jlss_id_exitstatus_c[]; 
const char jlss_id_exitstatus_c[] = "@(#)$Id: exitstatus.c,v 1.2 2008/12/28 03:45:18 jleffler Exp $"; 
#endif /* lint */ 

int main(int argc, char **argv) 
{ 
    pid_t pid; 

    err_setarg0(argv[0]); 

    if (argc < 2) 
     err_usage("cmd [args...]"); 

    if ((pid = fork()) < 0) 
     err_syserr("fork() failed: "); 
    else if (pid == 0) 
    { 
     /* Child */ 
     execvp(argv[1], &argv[1]); 
     return(1); 
    } 
    else 
    { 
     pid_t corpse; 
     int status; 
     corpse = waitpid(pid, &status, 0); 
     if (corpse != pid) 
      err_syserr("waitpid() failed: "); 
     printf("0x%04X\n", status); 
    } 
    return(0); 
} 

遗漏码,stderr.cstderr.h,可以很容易地在本质上我的任何出版计划中找到。如果您急需它,请从程序SQLCMD处获取IIUG Software Archive;或者,通过电子邮件与我联系(见我的个人资料)。

相关问题