Perl 系统调用中的 => 和逗号运算符
The => and comma operators in a Perl system call
我是 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, the specific plugin in question is at https://github.com/shutter-project/shutter/blob/master/share/shutter/resources/system/plugins/perl/spwatermark/spwatermark
找到
启动插件时会显示一个对话框,用户可以在其中输入一些字段。对话框如下所示:
首次启动时,它会执行函数 fct_imagemagick_watermark()
(从第 254 行开始)。每当单击刷新或保存按钮时,都会发送一个重新启动此功能的信号(信号在第 164 和 167 行中发送)。在该函数内部,调用了一个子函数 apply_effect()
,它从第 341 行开始,在第 354 行和第 365 行包括对 imagemagick 命令的两个系统调用。实际上,当通过刷新或保存按钮调用该函数时,两个系统调用都会失败,但是如果使用反引号和连接点编写命令,则这些命令有效。
$gravity_combo->get_active_text
是对话框右上角下拉菜单的值(例如“居中”)。 227行左右生成了两个tmpfilename变量,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"
我想你可以 space 像这样输出参数:
my $cmd =" composite $tempfilename
-gravity $gravity_combo->get_active_text
$filename $tmpfilename2)
";
$cmd =~ tr/\n//d;
$result = `$cmd`;
=> 也称为“胖逗号”,通常用于哈希结构,但您这里没有。
好的,我现在明白了。 "$gravity_combo->get_active_text" 是一个可执行函数。
如果它在引号内,它将不会执行。
这个有用吗?
my $cmd = " composite ". $tempfilename.
" -gravity ". $gravity_combo->get_active_text().
" $filename ". $tmpfilename2;
好的,我一直在看评论。我回到原来的问题并实现了一个重力对象,以便调用语法有效。当我在下面调用 foo() 而不是 system() 时,它看起来“有效”并且返回的这个字符串也应该在系统调用中有效。考虑这段代码:
use strict;
use warnings;
my $tmpfilename = "temp";
my $filename = "somefile";
my $tmpfilename2 = "temp2";
package Gravity;
use strict;
use warnings;
sub new
{
my $class = shift;
my $me = {};
bless($me, $class);
$me ->{active_text} = "ABC";
return $me;
}
sub get_active_text
{
my $me = shift;
return $me->{active_text};
}
my $gravity_combo = new Gravity;
## call foo() instead of system() and see what it prints...
foo (
composite => $tmpfilename,
-gravity => $gravity_combo->get_active_text,
$filename => $tmpfilename2
);
sub foo
{
print "@_\n"; #system ("@_"); should work?
}
# prints: composite temp -gravity ABC somefile temp2
据我所知,创建一个像 foo() 这样的辅助函数,并让它生成一个字符串以传递给系统调用。看起来这可以防止陷入引用规则的泥潭。上面 foo() 的参数看起来“漂亮”(根据原始问题很好地格式化并且至少在我看来令人愉悦)。
没有足够的信息来完整回答,但我们可以解释其中的区别。它是双重的。
首先,"fat comma" 询问了
The =>
operator (sometimes pronounced "fat comma") is a synonym for the comma except that it causes a word on its left to be interpreted as a string if it begins with a letter or underscore and is composed only of letters, digits and underscores. This includes operands that might otherwise be interpreted as operators, constants, single number v-strings or function calls.
所以,它左边的单词被(双)引号简单粗暴地引用了——而一些原本可能被视为运算符或函数的字符或字符串现在却不是。这应该不重要,因为只有 $filename
是一个变量, 应该很清楚。
那么基于粗逗号的行就是一个简单的列表
system(
"composite", $tmpfilename,
"-gravity", $gravity_combo->get_active_text,
$filename, $tmpfilename2
);
($filename
无论如何都会被插值,所以我省略了不需要的引号)
第二个区别更微妙,负载也更大:当您给 system
一个列表时,它不会调用 shell 而是直接使用系统调用,其中第一个参数是命令名称和其他名称作为参数传递给该命令。
您发现有效的 运行 命令的另一种方法是不同的: qx (反引号)形成一个字符串,其中包含传递给它的任何内容,扫描它以查找 shell 元字符,如果找到任何元字符,则将其传递给 shell 以执行。† 可能会有细微的变化,但主要是它的作用。那可能很不一样。
所以一个明显的猜测是那里的某些东西需要 shell,它在反引号 (qx
) 方法中得到,而不是在 system
下的列表。一种测试方法是在 this
上强制使用 shell
system('bash', '-c', "composite $tmpfilename ...");
(或者,用空格连接:join(' ', 'composite', $tmpfilename, ...)
就像你一样)
甚至可能 composite
命令本身需要 shell 之外的 运行,由于某些环境细节等原因。 (因为从评论中的链接看来,其余参数似乎是纯数字或字符串和文件名。)这只是一个简单的猜测。
我们确实需要查看详细信息,但希望这对某些人有所帮助。
† 当您将命令组合成字符串时,即使将其传递给 system
也会以相同的方式处理。
我是 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, the specific plugin in question is at https://github.com/shutter-project/shutter/blob/master/share/shutter/resources/system/plugins/perl/spwatermark/spwatermark
找到启动插件时会显示一个对话框,用户可以在其中输入一些字段。对话框如下所示:
首次启动时,它会执行函数 fct_imagemagick_watermark()
(从第 254 行开始)。每当单击刷新或保存按钮时,都会发送一个重新启动此功能的信号(信号在第 164 和 167 行中发送)。在该函数内部,调用了一个子函数 apply_effect()
,它从第 341 行开始,在第 354 行和第 365 行包括对 imagemagick 命令的两个系统调用。实际上,当通过刷新或保存按钮调用该函数时,两个系统调用都会失败,但是如果使用反引号和连接点编写命令,则这些命令有效。
$gravity_combo->get_active_text
是对话框右上角下拉菜单的值(例如“居中”)。 227行左右生成了两个tmpfilename变量,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"
我想你可以 space 像这样输出参数:
my $cmd =" composite $tempfilename
-gravity $gravity_combo->get_active_text
$filename $tmpfilename2)
";
$cmd =~ tr/\n//d;
$result = `$cmd`;
=> 也称为“胖逗号”,通常用于哈希结构,但您这里没有。
好的,我现在明白了。 "$gravity_combo->get_active_text" 是一个可执行函数。 如果它在引号内,它将不会执行。 这个有用吗?
my $cmd = " composite ". $tempfilename.
" -gravity ". $gravity_combo->get_active_text().
" $filename ". $tmpfilename2;
好的,我一直在看评论。我回到原来的问题并实现了一个重力对象,以便调用语法有效。当我在下面调用 foo() 而不是 system() 时,它看起来“有效”并且返回的这个字符串也应该在系统调用中有效。考虑这段代码:
use strict;
use warnings;
my $tmpfilename = "temp";
my $filename = "somefile";
my $tmpfilename2 = "temp2";
package Gravity;
use strict;
use warnings;
sub new
{
my $class = shift;
my $me = {};
bless($me, $class);
$me ->{active_text} = "ABC";
return $me;
}
sub get_active_text
{
my $me = shift;
return $me->{active_text};
}
my $gravity_combo = new Gravity;
## call foo() instead of system() and see what it prints...
foo (
composite => $tmpfilename,
-gravity => $gravity_combo->get_active_text,
$filename => $tmpfilename2
);
sub foo
{
print "@_\n"; #system ("@_"); should work?
}
# prints: composite temp -gravity ABC somefile temp2
据我所知,创建一个像 foo() 这样的辅助函数,并让它生成一个字符串以传递给系统调用。看起来这可以防止陷入引用规则的泥潭。上面 foo() 的参数看起来“漂亮”(根据原始问题很好地格式化并且至少在我看来令人愉悦)。
没有足够的信息来完整回答,但我们可以解释其中的区别。它是双重的。
首先,"fat comma" 询问了
The
=>
operator (sometimes pronounced "fat comma") is a synonym for the comma except that it causes a word on its left to be interpreted as a string if it begins with a letter or underscore and is composed only of letters, digits and underscores. This includes operands that might otherwise be interpreted as operators, constants, single number v-strings or function calls.
所以,它左边的单词被(双)引号简单粗暴地引用了——而一些原本可能被视为运算符或函数的字符或字符串现在却不是。这应该不重要,因为只有 $filename
是一个变量, 应该很清楚。
那么基于粗逗号的行就是一个简单的列表
system(
"composite", $tmpfilename,
"-gravity", $gravity_combo->get_active_text,
$filename, $tmpfilename2
);
($filename
无论如何都会被插值,所以我省略了不需要的引号)
第二个区别更微妙,负载也更大:当您给 system
一个列表时,它不会调用 shell 而是直接使用系统调用,其中第一个参数是命令名称和其他名称作为参数传递给该命令。
您发现有效的 运行 命令的另一种方法是不同的: qx (反引号)形成一个字符串,其中包含传递给它的任何内容,扫描它以查找 shell 元字符,如果找到任何元字符,则将其传递给 shell 以执行。† 可能会有细微的变化,但主要是它的作用。那可能很不一样。
所以一个明显的猜测是那里的某些东西需要 shell,它在反引号 (qx
) 方法中得到,而不是在 system
下的列表。一种测试方法是在 this
system('bash', '-c', "composite $tmpfilename ...");
(或者,用空格连接:join(' ', 'composite', $tmpfilename, ...)
就像你一样)
甚至可能 composite
命令本身需要 shell 之外的 运行,由于某些环境细节等原因。 (因为从评论中的链接看来,其余参数似乎是纯数字或字符串和文件名。)这只是一个简单的猜测。
我们确实需要查看详细信息,但希望这对某些人有所帮助。
† 当您将命令组合成字符串时,即使将其传递给 system
也会以相同的方式处理。