GNU time returns 与打印出来的信号不同

GNU time returns different signal than it prints out

虽然 运行 cronjobs 并使用 check_mk 中的 mk-job 来监视其结果,但我偶然发现了这个:

bash:

$ /usr/bin/time -f "time_exit: %x" timeout -s SIGKILL 2s sleep 10; echo "shell_exit: $?"
Command terminated by signal 9
time_exit: 0
shell_exit: 137

/usr/bin/time 返回的退出代码不同于它写入格式化输出的退出代码:

time_exit != shell_exit

为什么?

但是当使用默认的 SIGHUP 信号时,退出代码匹配:

$ /usr/bin/time -f "time_exit: %x" timeout -s SIGHUP 2s sleep 10; echo "shell_exit: $?"
Command exited with non-zero status 124
time_exit: 124
shell_exit: 124

与此同时,我将使用 timeout -k 10s 2s ...,它将首先发送 SIGHUP,并在 10 秒后发送 SIGKILL,如果进程仍然是 运行。希望SIGHUP能妥善阻止。

背景

check_mk 提供 mk-job 来监控作业执行。 mk-job 使用 time 来记录执行时间和退出代码。

man time:

The time command returns when the program exits, stops, or is terminated by a signal. If the program exited normally, the return value of time is the return value of the program it executed and measured. Otherwise, the return value is 128 plus the number of the signal which caused the program to stop or terminate.

man timeout:

... It may be necessary to use the KILL (9) signal, since this signal cannot be caught, in which case the exit status is 128+9 rather than 124.

GNU time%x 仅当进程 正常 退出时才有意义,而不是被信号杀死。

[STEP 101] $ /usr/bin/time -f "%%x = %x" bash -c 'exit 2'; echo '$? = '$?
Command exited with non-zero status 2
%x = 2
$? = 2
[STEP 102] $ /usr/bin/time -f "%%x = %x" bash -c 'exit 137'; echo '$? = '$?
Command exited with non-zero status 137
%x = 137
$? = 137
[STEP 103] $ /usr/bin/time -f "%%x = %x" bash -c 'kill -KILL $$'; echo '$? = '$?
Command terminated by signal 9
%x = 0
$? = 137
[STEP 104] $

对于time timeout -s SIGKILL 2s sleep 10timeout正常退出137,不会被SIGKILL杀死,就像bash -c 'exit 137' 在我的例子中。


更新:

查看时间来源code发现%x不管进程是否正常退出都是盲目调用WEXITSTATUS()

655             case 'x':           /* Exit status.  */
656               fprintf (fp, "%d", WEXITSTATUS (resp->waitstatus));
657               break;

在 Git master 中添加了新的 %Tx:

549             case 'T':
550               switch (*++fmt)
551                 {
...
575                 case 'x': /* exit code IF terminated normally */
576                   if (WIFEXITED (resp->waitstatus))
577                     fprintf (fp, "%d", WEXITSTATUS (resp->waitstatus));
578                   break;

并且来自 Git 大师的 time --help 输出:

  ...

  %Tt  exit type (normal/signalled)
  %Tx  numeric exit code IF exited normally
  %Tn  numeric signal code IF signalled
  %Ts  signal name IF signalled
  %To  'ok' IF exited normally with code zero

  ...