无法使用 perl 中的系统命令获取已编译 C 程序执行的标准错误
Posted
技术标签:
【中文标题】无法使用 perl 中的系统命令获取已编译 C 程序执行的标准错误【英文标题】:Cannot get stderr of the execution of a compiled C program with the system command in perl 【发布时间】:2021-05-08 03:31:12 【问题描述】:我写了一个对我非常有用的漂亮的小 perl 脚本。它允许我编译和执行 C 指令,就好像它是解释语言的指令一样。 它是我用来学习 C 语言的各种 C 编程 IDE。
这是我的使用方法:
crepl -Istdio 'char * str="text"; printf("%s\n", str);'
OUTPUT
text
crepl -Istdio,string 'char * str="text"; int i; for(i=0; i < strlen(str);i++)printf("%c", str[i]); printf("\n");'
OUTPUT
text
crepl -Istdio 'char * str="text"; int i=0; while(str[i] != '\''\0'\'')printf("%c", str[i]); i++; printf("\n");'
OUTPUT
text
这是脚本:
#!/usr/bin/perl
# this script requires this line in /etc/fstab :
#tmpfs /tmp/ram/ tmpfs defaults,noatime,nosuid,nodev,mode=1777,size=32M 0 0
use strict;
use warnings;
use autodie;
my @include;
$,="\n";
$\="\n";
if (not @ARGV) exit
elsif ($ARGV[0] =~ m/^-I/)
$ARGV[0] =~ s/^-I//;
@include = split /,/, $ARGV[0];
shift;
#my $source_code = "/tmp/ram/c_program.c"; # requires adding a line in /etc/fstab
#my $compiled_code = "/tmp/ram/c_program.o"; # requires adding a line in /etc/fstab
my $source_code = "./.c_program.c";
my $compiled_code = "./.c_program.o";
open my $FH, ">", $source_code;
foreach (@include)
print $FH "#include <$_.h>";
print $FH "int main(int argc, char *argv[]) ";
print $FH $ARGV[0];
print $FH "return 0;";
print $FH "";
close $FH;
system "gcc", $source_code, "-o", $compiled_code;
system $compiled_code;
我遇到的问题是我没有收到运行时发生的错误消息。 (虽然我确实收到了编译错误消息。)
如果我这样做:
crepl -Istdio 'char * str="text"; char * copy; int i=0; while(str[i] != '\''\0'\'')copy[i]=str[i]; i++; printf("%s\n", copy);'
我没有输出。但我真的应该得到这个:
分段错误(核心转储)
因为我忘记了 malloc。复制字符串的正确方法是这样:
crepl -Istdio,string,stdlib 'char * str="text"; char * copy=malloc(strlen(str)); int i=0; while(str[i] != '\''\0'\'')copy[i]=str[i]; i++; printf("%s\n", copy);'
这很烦人。如果我没有收到 Segmentation Fault 之类的消息,我学习 C 就会有困难。
我已经尝试替换
系统 $compiled_code;
通过
系统 "$compiled_code 2>&1";
或
打印`$compiled_code 2>&1`;
但两者都不起作用。
你知道我可以如何修改我的脚本来获取这些错误消息吗?
谢谢。
【问题讨论】:
如果不使用autodie
会怎样?另见How to get Capture::Tiny to print stderr and stdout upon failure?
如果你的意思是它解决了问题,那么不,它没有。但是你的意思是什么是有用的,如果文件句柄出现错误,它用于退出程序并显示错误消息
很抱歉,即使这个模块有效,我也可能不会使用它,因为它会减慢脚本速度,因为必须加载模块。这很烦人。我想让我的脚本保持适度的速度
我刚刚看到我的问题有点重复,而且 prog-fh 的解决方案也在那里 ***.com/questions/18332846/…
"...我可能不会使用它,因为它会稍微减慢脚本速度..." - 这是误导。虽然任何库都会让事情变慢一点,但我看不出你会如何注意到那些
【参考方案1】:
您有时在终端中看到的Segmentation fault (core dumped)
消息不是由您启动的进程产生的,而是由启动该进程的shell 产生的。
当它启动一个进程时,shell 会通过类似于man 3 waitpid
的系统调用来等待它。
这样的系统调用告诉进程是成功退出(使用return
或_exit()
)还是被信号杀死。
在最后一种情况下,shell 会显示一条特定于导致提前终止的信号 (man 3 strsignal
) 的消息。
在您的特定情况下,这不是启动您用 C 编写的进程的 shell,而是 perl 解释器。 您的进程被杀死不会使 perl 也被杀死,因此您的 shell 不会显示这样的消息。
我不会编写 perl,但我确信您可以将 system $compiled_code;
替换为与 fork()/exec()/waitpid()/strsignal()
等效的东西。
使用this page的结尾, 我认为您可以在脚本末尾尝试此操作。
system $compiled_code;
my $status = $?;
if ($status == -1)
print "failed to execute: $!\n";
elsif ($status & 127)
printf "child died with signal %d, %s coredump\n",
($status & 127), ($status & 128) ? 'with' : 'without';
else
printf "child exited with value %d\n", $status >> 8;
【讨论】:
谢谢 我不知道分段错误错误是由 shell 发送的。我像你一样复制粘贴了系统函数文档中的代码,我猜它解决了我的问题。我只记得 11 代表分段错误。我只是删除了代码的 else 部分,因为它只是噪音 @WhiteMist 另请注意,Perl 中有很好的库可用于运行和管理外部程序,正如帖子所说,它们可以完全“替换system ...
”。从简单到强大,例如IPC::System::Simple、Capture::Tiny、IPC::Run3、IPC::Run
是的,抱歉,我仍然需要了解 *** 的工作原理。这是一个好主意,你建议用 fork、exec、waitpid 和 strsignal 替换 system。我已经有执行 fork exec 的 perl 脚本,我必须有最后 2 个。我不能正确知道,因为我还不知道如何使用系统调用来执行程序。这也是我一开始想学习 C 的原因之一。以上是关于无法使用 perl 中的系统命令获取已编译 C 程序执行的标准错误的主要内容,如果未能解决你的问题,请参考以下文章
无法通过从两个不同子例程传递给新子例程的值来执行计算:Perl