使用strace跟踪时如何捕获子命令及单元测试的退出码?
如何捕获strace跟踪的子命令退出码
当然可以捕获被strace跟踪的子命令的退出码!strace默认会传递被跟踪进程的退出状态,不过具体实现要注意你调用strace的方式,尤其是在管道或子shell场景下。下面分两部分解答你的问题:
一、通用场景:直接通过strace运行命令时捕获退出码
当你直接用strace启动并跟踪一个命令时,strace会将被跟踪进程的退出码返回给父shell。比如:
strace -e trace=file php your_script.php echo $? # 这里输出的就是php脚本的退出码
不过要注意:如果strace自身出现错误(比如权限不足、参数错误),$?会返回strace自己的错误码,而非被跟踪进程的。你可以通过检查退出码是否符合预期来区分这种情况。
二、针对你的具体命令场景
你的命令是通过Perl的open管道调用strace来跟踪PHPUnit测试:
open(IN, "-|", "strace -ff $pid -e trace=file @cmd 2>&1")
这里有几个关键细节需要调整和说明:
1. 修正strace的参数错误
你命令里的$pid是多余的,甚至会导致错误:-p $pid是用来attach到已运行的进程,而你是要启动新的PHPUnit命令并跟踪它。正确的strace命令应该去掉$pid,改为:
strace -ff -e trace=file @cmd 2>&1
-ff参数已经会自动跟踪@cmd启动的所有子进程,并按进程ID生成对应的日志文件,完全满足你跟踪单元测试涉及文件的需求。
2. 在Perl中捕获PHPUnit的退出码
在Perl的管道open之后,当你关闭管道句柄IN时,可以通过特殊变量$?获取子进程(也就是strace命令)的退出状态。而strace的退出状态就是被跟踪的PHPUnit命令的退出码(除非strace自身异常终止)。
具体的处理代码示例:
# 修正后的open调用 open(IN, "-|", "strace -ff -e trace=file php -d auto_prepend_file=auto_prepend_for_tests.php /data/tests/sdk/bin/phpunit.phar --configuration /data/tests/conf/database.xml my_test.php 2>&1") or die "无法打开管道: $!"; # 读取strace输出的逻辑(比如处理文件访问日志) while (<IN>) { # 处理每一行输出 print $_; } # 关闭管道并获取退出状态 close(IN); my $exit_status = $?; # 解析退出状态 if ($exit_status == -1) { print "strace命令执行失败\n"; } elsif ($exit_status & 127) { printf "strace被信号%d终止\n", $exit_status & 127; } else { my $phpunit_exit_code = $exit_status >> 8; printf "PHPUnit测试的退出码是: %d\n", $phpunit_exit_code; }
关键说明
$?是一个16位的变量:低7位存储终止信号,高8位存储进程的退出码。所以用$exit_status >> 8就能提取出实际的退出码。- 如果
$exit_status & 127不为0,说明strace是被信号杀死的(比如SIGINT),这时候无法获取PHPUnit的正常退出码。
内容的提问来源于stack exchange,提问作者Prathyusha
相关产品推荐
相关产品推荐

