使用哈希值中存储的文件句柄的语法错误

时间:2019-06-19 10:48:15

标签: perl syntax-error filehandle perl5

我正在尝试使用单行代码根据行本身字段的内容将从输入源读取的行写入不同的文件。

我的方法是使用散列来存储文件句柄,以避免多次打开相同的文件,一旦在读取的新行中找到以前未出现过的字段的值,就动态向该散列添加键

但是使用散列值存储文件句柄并使用常见的print / printf调用,例如

print $hash{ $field_value } "String"

导致编译错误。 例如,用$hash{ $field_value }替换STDERR会产生干净的编译结果。

在下面的示例中有一个单线示例。

$ cat /tmp/input_file 
mail1.sql:INSERT INTO
mail2.sql:INSERT INTO
mail3.sql:INSERT INTO
mail4.sql:INSERT INTO
mail6.sql:INSERT INTO
mail7.sql:INSERT INTO
mail8.sql:INSERT INTO
mail9.sql:INSERT INTO
maildev.sql:INSERT INTO

$ perl -C -nE '
m{^(?<server>mail[^.]+)\.sql:(?<string>INSERT INTO)};
exists $fd->{$+{server}} or open($fd->{$+{server}}, ">>", "/tmp/". $+{server}.".tmp.sql");
print sprintf(qq{server %s.domain.tld command %s;\n}, $+{server}, $+{string});
' /tmp/input_file 
server mail1.domain.tld command INSERT INTO;
server mail2.domain.tld command INSERT INTO;
server mail3.domain.tld command INSERT INTO;
server mail4.domain.tld command INSERT INTO;
server mail6.domain.tld command INSERT INTO;
server mail7.domain.tld command INSERT INTO;
server mail8.domain.tld command INSERT INTO;
server mail9.domain.tld command INSERT INTO;
server maildev.domain.tld command INSERT INTO;

# The files were opened, creating them. print-ing to STDOUT works fine.

$ ls -1  /tmp/mail*sql
/tmp/mail1.tmp.sql
/tmp/mail2.tmp.sql
/tmp/mail3.tmp.sql
/tmp/mail4.tmp.sql
/tmp/mail6.tmp.sql
/tmp/mail7.tmp.sql
/tmp/mail8.tmp.sql
/tmp/mail9.tmp.sql
/tmp/maildev.tmp.sql

# Now using $fd->{$+{server}} as filehandle for print

$ perl -C -nE '
m{^(?<server>mail[^.]+)\.sql:(?<string>INSERT INTO)};
exists $fd->{$+{server}} or open($fd->{$+{server}}, ">>", "/tmp/". $+{server}.".tmp.sql");
print $fd->{$+{server}} sprintf(qq{server %s.domain.tld command %s;\n}, $+{server}, $+{string});
' /tmp/input_file
syntax error at -e line 4, near "} sprintf"
syntax error at -e line 5, near ";}"
Execution of -e aborted due to compilation errors.

# Simplifying further

$ perl -C -nE '
my $a = "test";                                      
exists $fd->{$a} or open($fd->{$a}, ">>", "/tmp/". $a.".tmp.sql");
print $fd->{$a} sprintf(qq{AAA %s AAA\n}, $a);
' /tmp/input_file
syntax error at -e line 4, near "} sprintf"
BEGIN not safe after errors--compilation aborted at -e line 4.

我已经尝试使用perl 5.22和5.30进行此操作,只是为了检查它是否是最近修复的某种错误。

也许我缺少明显的东西,但是我看不到。

有人有主意吗?

谢谢。

1 个答案:

答案 0 :(得分:5)

您需要将手柄包裹在裸露的块中。

print { $hash{ $field_value } } "String";

这在print perldoc中有记录。

  

如果将句柄存储在数组或哈希中,或者通常在任何时候   您所使用的表达式比裸字句柄或   普通的,未下标的标量变量来检索它,您将必须   使用一个返回filehandle值的块,在这种情况下   LIST不能省略:

print { $files[$i] } "stuff\n";
print { $OK ? *STDOUT : *STDERR } "stuff\n";