为什么我的Perl系统调用会因点而失败?

为什么我的Perl系统调用会因点而失败?,perl,system,Perl,System,我是Perl的初学者,在使用“系统”调用时遇到了一些问题。下面是我尝试执行2个shell命令的一段代码: # First command is : # dot -Tpng $dottmpfile > $pngfile # Second command is : # rm $dottmpfile if (!($pngfile eq "")) { my @args = ("dot", "-Tpng", $dottmpfile, " > ", $pngfile); system

我是Perl的初学者,在使用“系统”调用时遇到了一些问题。下面是我尝试执行2个shell命令的一段代码:

# First command is :
# dot -Tpng $dottmpfile > $pngfile
# Second command is :
# rm $dottmpfile

if (!($pngfile eq "")) {
  my @args = ("dot", "-Tpng", $dottmpfile, " > ", $pngfile);
  system (join (' ' , @args ))
    or die "system @args failed : $!";

  unlink $dottmpfile;
}
编辑:这是我现在的代码,我仍然得到一个错误:

system dot -Tpng toto.dot  >  toto.png failed : Inappropriate ioctl for device at /home/claferri/bin/fractal.pl line 79.

我曾经生成过这段代码。

您正在使用
告诉shell将输出重定向到文件,但是通过调用
系统列表
,您正在绕过shell。因此,您可以使用:

system ( join (' ' , @args ) ); 
if ( defined $pngfile and $pngfile ne '') {
    my @args = (dot => '-Tpng', $dottmpfile, "-o$pngfile");
    if ( system @args ) {
        warn "'system @args' failed\n";
        my $reason = $?;
        if ( $reason == -1 ) {
            die "Failed to execute: $!";
        }
        elsif ( $reason & 0x7f ) {
            die sprintf(
                'child died with signal %d, %s coredump',
                ($reason & 0x7f),  
                ($reason & 0x80) ? 'with' : 'without'
            );
        }
        else {
            die sprintf('child exited with value %d', $reason >> 8);
        }
    }
    warn "'system @args' executed successfully\n";
    unlink $dottmpfile;
}

“点”是否在
路径中可执行?它是否具有可执行权限?这段代码会导致哪种特定错误

根据。

看,这似乎是正确的,注意:

如果列表中有多个参数,或者列表是一个具有多个值的数组,则使用列表其余部分提供的参数启动列表第一个元素提供的程序。如果只有一个标量参数,将检查该参数是否有shell元字符,如果有,则将整个参数传递给系统的命令shell进行解析

您正在调用
系统列表
,因此
最终被传递到
,而不是由shell解释

我建议您继续使用
系统列表
,因为它比通过shell传递所有内容要安全一点。根据文档,您可以使用
-o
选项将输出文件指定为
,这样做

如果你真的想点上你的is和交叉你的ts(双关语不是有意的),那么你可以使用:

system ( join (' ' , @args ) ); 
if ( defined $pngfile and $pngfile ne '') {
    my @args = (dot => '-Tpng', $dottmpfile, "-o$pngfile");
    if ( system @args ) {
        warn "'system @args' failed\n";
        my $reason = $?;
        if ( $reason == -1 ) {
            die "Failed to execute: $!";
        }
        elsif ( $reason & 0x7f ) {
            die sprintf(
                'child died with signal %d, %s coredump',
                ($reason & 0x7f),  
                ($reason & 0x80) ? 'with' : 'without'
            );
        }
        else {
            die sprintf('child exited with value %d', $reason >> 8);
        }
    }
    warn "'system @args' executed successfully\n";
    unlink $dottmpfile;
}

系统
成功时返回0,“失败”时返回非零。这与大多数习惯用法的外观相反,并且有点违反直觉,但是对于
system
调用,您应该使用如下表达式:

system($command) and warn "system $command: failed $?\n";   # and not or


如果你只是想让它快速运行,将整行合并成一个字符串,并在其周围加上反勾:即$result=`dot-Tpng$dottmpfile>$pngfile`;请参见此处:。此外,要删除文件,请使用
unlink()
。无需呼叫系统
rm
您应该使用$!而不是美元这会给你错误信息,而不是错误代码,并且几乎总能告诉你出了什么问题。你是收到了错误信息还是只是想让你的代码更干净?@PP将列表和单个字符串传递给
系统
(或
qx
)之间有着至关重要的区别@pavun将列表和单个字符串传递到
系统(或
qx
)之间有着至关重要的区别。事实上,阻止claferri的代码工作的是列表而不是字符串,因为它依赖于shell功能。@hobbs:如果我明白你的意思,问题是列表中没有空格,join函数用空格分隔的元素从列表中生成字符串?@hobbs我错过了
。谢谢你的提示@帕文编辑了你的答案,添加了解释,并将我的反对票转换为赞成票。抱歉误解。这似乎几乎是正确的,因为该命令确实生成了png输出文件,但我得到了“失败:设备在/home/claferri/bin/fractal.pl第79行的ioctl不正确”。我的程序在到达脚本结尾之前退出(unkink$dottmpfile)。当然,dot是一个众所周知的debian软件包,所以这不可能是问题的根源。。。我从来没有听说过那件事。。。感谢您提供的信息这是一个图形工具(包:graphviz),用于从描述图形的文本文件创建图形图像(例如png文件),对我来说非常有用;)我不明白你向我推荐什么?还是你想说“不会”?那我还应该用什么?我只需要处理dot命令,并在$pngfile中获取它的输出(使用“>”是我的第一个反射,因为这是我在bash中执行的方式,但我想在perl中可能有更好的方法来执行)@claferri我建议您保留
系统列表
表单,并使用
-o
选项指定输出文件,而不是shell重定向操作符
。我仍然会得到“failed:unjusted ioctl for device at/home/claferri/bin/fractal.pl第79行”。我认为它可能来自其他方面。。。我正在查看代码的前一部分。事实上,只需注释--or die“system@args failed:$!”;--似乎解决了这个问题,不知道为什么…使用您的代码也可以完美地工作,并且在发生错误时应该明确!