在 Linux 中发出更多命令后,有没有办法获取进程退出状态?

在 Linux 中发出更多命令后,有没有办法获取进程退出状态?

如果我发出了很多命令,并且我想要 100 个命令前退出的进程的退出状态。 Linux 中是否有结构、文件位置或变量我可以访问所有已退出的进程并查看有关它们的信息?

答案1

如果使用 GNU 6.6.3 或更高版本启用了 BSD 进程记帐(accton on已发布) ,您可以从或(或系统上存储进程记帐数据的任何位置)获取该信息。acctlastcomm --debugdump-acct /var/log/account/pact

$ perl -e '退出 123'
$lastcomm--调试| grep perl
当前记录:perl |v3| 0.00| 0.00| 0.00| 1000| 1000| 26328.00| 0.00| 332| 8530| |     123|pts/1 |2018 年 9 月 19 日星期三 20:21:26
$ dump-acct /var/log/account/pacct | grep perl
Perl |v3| 0.00| 0.00| 0.00| 1000| 1000| 26328.00| 0.00| 332| 8530| |     123|pts/1 |2018 年 9 月 19 日星期三 20:21:26

您可以在倒数第三个字段中获得退出代码以及它是否被杀死(但不是信号编号,请参阅@mosvy 对此的回答)在第四个最后一个。

答案2

如果您使用的是 debian,则可以安装该acct软件包以启用进程记帐,但请注意,既不显示lastcomm --debug也不会dump-acct显示退出状态或终止进程的信号之类的内容。

如果为了获取该数据,您可以使用如下脚本:

$ cat pacct.pl
#! /usr/bin/perl
use strict;
use Config;
printf "%-7s %6s %6s  %8s %8s  %s\n",
        'STATUS', 'UID', 'PID', 'BTIME', 'ETIME', 'COMMAND';
my @sig = split ' ', $Config{sig_name};
$/ = \64;
while(<>){
        my @f = unpack 'CCSL6fS8A*', $_;
        my ($flag, $version, $tty, $exitcode, $uid, $gid, $pid, $ppid,
                $btime, $etime, $utime, $stime, $mem, $io, $rw,
                $minflt, $majflt, $swaps, $cmd) = @f;
        my $s = $exitcode & 0x7f;
        my $status = $s ?  "SIG$sig[$s]" : $exitcode >> 8;
        printf "%-7s %6d %6d  %02d:%02d:%02d %8.2f  %-16s\n",
                $status, $uid, $pid,
                (localtime $btime)[2,1,0],
                $etime / 100,
                $cmd;
}

# perl pacct.pl /var/log/account/pacct
# tail -f /var/log/account/pacct | perl pacct.pl

这假定日志文件格式的版本 3 -- 请参阅acct.h

但请注意,这并不是很有用,因为日志文件中只包含进程/线程名称(即可执行文件的基本名称,截断为 15 个字节,可以很容易地用 伪造prctl(PR_SET_NAME)),而不是路径可执行文件或调用它的参数。

如果您想扩展该脚本以也显示stimeutime等字段,这可能很有用:

# translate comp_t to float
# utime, stime, mem, minflt, majflt are in the comp_t format
# io, rw, swaps are never set; they're purely decorative
sub comp2f {
        my $m = $_[0] & 0x1fff; my $e = $_[0] >> 13; $m * 8 ** $e;
}

笔记:acct您还可以使用以下命令打开进程记帐,而不是安装该包:

# mkdir /var/log/account
# perl -e 'require "syscall.ph"; my $f = shift;
  open my $h, ">>", $f or die "open >>$f: $!" if $f;
  $! = -syscall SYS_acct(), $f // 0 and die "acct $f: $!";
' /var/log/account/pacct

答案3

  set -o pipefail 

非常接近你想要的;它会

在管道的所有组件完成之前,管道不会完成,返回值将是最后一个失败的非零命令的值,如果没有命令失败,则返回值为零。

因此,如果您有 40 个命令通过管道连接在一起,并且第三个命令给出的返回代码为 8,而其余命令成功完成,则总体返回代码将为 8。要找出哪个命令给出错误的返回代码将很棘手。

相关内容