【问题标题】:Why does my Perl system call fail with dot?为什么我的 Perl 系统调用失败并带有点?
【发布时间】:2010-03-18 11:46:03
【问题描述】:

我是 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.

我使用system 生成了这段代码。

【问题讨论】:

  • 如果你只是想让它快速运行,请将整行合并为一个字符串并在其周围加上反引号:即 $result = `dot -Tpng $dottmpfile > $pngfile`;
  • 见这里:stackoverflow.com/questions/2461472/…。此外,要删除文件,请使用unlink()。无需调用系统rm
  • 你应该使用 $!而不是 $? - 这会给你错误信息而不是错误代码,而且几乎总是会告诉你出了什么问题。
  • 您是收到错误消息还是只是想让您的代码更简洁?
  • @PP 将列表与单个字符串传递给system(或qx)之间存在关键区别。

标签: perl system


【解决方案1】:

查看perldoc -f system,注意:

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

您正在调用system LIST,因此> 最终被传递给dot,而不是被shell 解释。

我建议您继续使用system LIST,因为它比通过外壳传递所有内容要安全一些。根据文档,您可以通过使用-o 选项到dot 来指定输出文件,所以这样做。

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

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;
}

【讨论】:

  • 我不明白你向我推荐什么?还是你想说“不会”?那我还应该用什么?我只需要处理 dot 命令,并在 $pngfile 中获取它的输出(使用 '>' 是我的第一个反射,因为这是我在 bash 中执行此操作的方式,但我猜在 perl 中可能有更好的方法来执行此操作)
  • @claferri 我建议您保留system LIST 表单并使用-o 选项而不是shell 重定向运算符> 指定输出文件。
  • 我仍然收到“失败:/home/claferri/bin/fractal.pl 第 79 行的设备不合适的 ioctl”。我认为它可能来自其他东西......我正在查看代码的前一部分。
  • 其实只是简单的注释掉 --or die "system @args failed : $!"; -- 好像解决了问题,不知道为什么……
  • 使用您的代码也可以完美运行,并且应该明确以防发生错误!
【解决方案2】:

您正在使用> 告诉shell 将输出重定向到一个文件,但是通过调用system LIST,您正在绕过shell。因此,您可以使用:

system ( join (' ' , @args ) ); 

system "@args";

【讨论】:

  • @pavun 将列表与单个字符串传递给system(或qx)之间存在关键区别。
  • 有,而且它是一个列表而不是字符串这一事实阻止了 claferri 的代码工作,因为它依赖于 shell 功能。
  • @hobbs :所以如果我明白你在说什么,问题是列表中没有空格,并且连接函数会从列表中创建一个带有空格分隔元素的字符串?
  • @hobbs 我错过了>。谢谢你的提示。 @pavun 编辑了您的答案以添加解释并将我的反对票转换为赞成票。对造成的误解深表歉意。
  • 这似乎几乎是正确的,因为该命令确实会生成 png 输出文件,但我得到“失败:/home/claferri/bin/fractal.pl 第 79 行的设备不合适的 ioctl”。并且我的程序在到达脚本末尾之前退出(unkink $dottmpfile)。
【解决方案3】:

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

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

if (system($command) != 0) { ... handle error ... }

【讨论】:

    【解决方案4】:

    PATH 中的“点”是否可执行?它有可执行权限吗?您在使用此代码时遇到了哪些具体错误?

    根据perldoc -f system,这似乎是正确的。

    【讨论】:

    • 当然,dot 是一个众所周知的 debian 包,所以这不可能是问题的根源。
    • ummmmmm ...我从来没有听说过那个^_^> ...谢谢你的信息
    • 这是一个图形工具(包:graphviz),用于从描述图形的文本文件创建图形图像(例如png文件),对我非常有用;)
    猜你喜欢
    • 1970-01-01
    • 2013-05-05
    • 1970-01-01
    • 1970-01-01
    • 2022-06-15
    • 1970-01-01
    • 2018-06-10
    • 1970-01-01
    • 2015-11-15
    相关资源
    最近更新 更多