Perl系统调用中的=>和逗号运算符
我是 Perl 的完全初学者,所以如果我的问题是微不足道的,请多多包涵。
我正在尝试修复一个相当大的 Perl 项目中的错误。通过一些反复试验和打印语句,我可以确定以下对 imagemagick 的系统调用是导致该错误的原因:
system(
composite => $tmpfilename,
-gravity => $gravity_combo->get_active_text,
$filename => $tmpfilename2
);
代码执行只是在这个系统调用处停止并且不发出任何输出。偶然地,当试图从这个系统调用中获取一些输出时,我发现如果我用以下内容替换系统调用
my $command = "composite " . $tmpfilename . " -gravity " . $gravity_combo->get_active_text . " " . $filename . " " . $tmpfilename2;
my $output = `$command`;
命令执行成功。
如您所见,逗号和 => 箭头被字符串连接替换,而 system() 被反引号替换,但除此之外,命令是相同的。
现在我想知道这是怎么发生的,是否有一种更优雅的方式来以工作方式编写命令。
附录:
我不想分享完整的代码,因为一方面,它是一个有点流行的应用程序的代码,我不想给人一种像我这样的业余爱好者正在研究它的印象(我不是开发人员)无论如何,只是一个团队成员,主要处理错误跟踪器上的用户支持);另一方面,我没想到在这种情况下更多的上下文会有所帮助。但由于一些用户要求更多的上下文,而且问题似乎比我最初假设的更复杂,我将提供完整的代码。
有问题的代码来自 Linux 桌面屏幕截图工具 Shutter 的插件。整个项目可以在https://github.com/shutter-project/shutter找到,有问题的特定插件在https://github.com/shutter-project/shutter/blob/master/share/shutter/资源/系统/插件/perl/spwatermark/spwatermark
启动插件时,会显示一个对话框,用户可以在其中输入一些字段。对话框如下所示:
首次启动时,它执行函数fct_imagemagick_watermark()(从第 254 行开始)。每当单击刷新或保存按钮时,都会发送一个信号以重新启动此功能(信号在第 164 行和第 167 行中发送)。在函数内部,一个子函数apply_effect()被调用,它从第 341 行开始,包括在第 354 和 365 行中对 imagemagick 命令的两个系统调用。实际上,当通过刷新或保存按钮调用该函数时,两个系统调用都失败,但如果它们成功,这些命令就会起作用使用反引号和连接点编写。
$gravity_combo->get_active_text是对话框右上角的下拉菜单的值(例如,“Center”)。两个 tmpfilename 变量是在第 227 行附近生成的,filename 变量来自主程序。
到目前为止,我对代码的理解到此为止,如果还有其他问题,请再次提问!
附录 2:原始问题中系统调用中变量的可能值:
$tmpfile = /tmp/euQgBTRpnf.png
$tmpfile2 = /tmp/eftbUp8eNf.png
$filename = /home/user/myimage.png
$gravity_combo = Gtk3::ComboBoxText=HASH(0x55e315db9568)
$gravity_combo->get_active-text = "Center"
回答
没有足够的信息来完全回答,但我们可以解释差异。这是双重的。
首先,有一个明显而简单的“胖逗号”被问到
该
=>运营商(有时读“胖逗号”)是不同的是它会导致在它的左边一个字被解释为一个字符串,如果它开始以字母或下划线,只有字母,数字和下划线是由逗号的代名词。这包括可能被解释为运算符、常量、单个数字 v 字符串或函数调用的操作数。
因此,它左边的单词被(双)引用,简单粗暴地放置 - 一些原本可能被视为运算符或函数的字符或字符串现在不是。这应该没有意义,因为只有$filenamewhich 是一个变量,而且应该很清楚。
然后基于脂肪逗号的行是一个简单的列表
system(
"composite", $tmpfilename,
"-gravity", $gravity_combo->get_active_text,
$filename, $tmpfilename2
);
($filename无论如何都会被插值,所以我省略了不需要的引号)
第二个区别更微妙且负载更大:当你给出system一个列表时,它不调用 shell 而是直接使用系统调用,其中第一个参数是命令名称,其他参数作为它的参数传递给该命令。
运行该命令的另一种方法是不同的:qx(反引号)形成传递给它的任何内容的字符串,扫描它以查找 shell 元字符,如果找到则将其传递给 shell 以执行。†可能会有细微的变化,但主要是这样。那很可能非常不同。
所以一个明显的猜测是那里的某些东西需要 shell,它通过反引号 ( qx) 方法获得,但在system. 一种测试方法是在这个上强制一个外壳
system('bash', '-c', "composite $tmpfilename ...");
(或者,用空格连接:join(' ', 'composite', $tmpfilename, ...)就像你一样)
甚至可能composite由于某些环境细节等原因,命令本身需要在 shell 之外运行。(因为从注释中的链接看来,其余参数是纯数字或字符串和文件名。)这只是一个简单的猜测。
确实我们需要查看详细信息,但希望这对某些人有所帮助。
†虽然您无论如何都将命令组合为字符串,因此即使将其传递给system,也会以相同的方式处理。