Perl 将变量传递给子程序
Posted
技术标签:
【中文标题】Perl 将变量传递给子程序【英文标题】:Perl Passing Variable to subroutines 【发布时间】:2021-08-12 10:44:17 【问题描述】:我正在尝试对现有的 Perl 脚本进行更改。我正在尝试添加一个在不同位置多次调用的子例程,并根据调用位置打印不同的输出。
基本上,它会创建一个文件并为业务团队编写一些业务消息(我是其中的一员,因此我是第一次使用 Perl 编码)。
我想要/正在尝试的是
Sub filemessage ($arg1)
open(fh, '>', $message_file);
print fh "$arg1/n";
close fh;
现在我想在很多地方(在其他子例程中)调用这个子例程,就像这样(已经有一个失败条件基于它被调用):
filemessage ("failed due to reason1")
filemessage ("failed due to reason2")
【问题讨论】:
【参考方案1】:Sub filemessage ($arg1) open(fh, '>', $message_file); print fh "$arg1/n"; close fh;
你们很亲密。
在 Perl 中,使用 sub
关键字(注意小写的 's')创建子例程。
换行符转义序列是\n
,而不是/n
。
如今,我们喜欢使用词法变量作为文件句柄(除了其他优点之外,这还可以在变量超出范围时自动关闭文件)。
使用>
作为文件模式将在您每次打开文件时创建一个新的空文件。所以它只会包含添加的最后一条消息。切换到>>
将附加消息。
您应该检查对open()
的调用的返回值,并在失败时采取适当的措施(通常终止程序是最好的选择)。
您应该在某处声明和定义$message_file
。由于子例程访问外部变量是个坏主意,因此您可能希望在子例程中执行此操作。
但你最大的问题是这条线:
sub filemessage ($arg1)
传统上 Perl 的子程序参数是在一个名为 @_
的数组中传递的,您需要自己提取它们。
my ($arg1) = @_;
但是从 Perl 5.20 开始,有一个实验性的 signatures
功能可以按照您的预期工作。
把所有这些放在一起,我们最终得到了这个:
# turn on signatures (put this with the other "use"
# statements at the top of your file).
use experimental 'signatures';
sub filemessage ($arg1)
my $message_file = 'log.txt';
open(my $fh, '>>', $message_file)
or die "Can't open [$message_file]: $!\n";
print $fh "$arg1\n";
【讨论】:
我以为你说他应该使用 append>>
。此外,die
消息中的换行符将防止错误打印发生死亡的行号,这很少是一个好主意。当普通功能如此简单易用时,我不建议新手使用实验性功能。
@TLP:>
是我现在修正的错字。我知道换行符是做什么的,我故意添加了它。在生产情况下,我可能会使用croak
而不是die
,因为对于像这样经常使用的子例程,调用子例程的位置通常比子例程中的行更有用。我认为这是一个实验性功能,它使 Perl 工作起来更像非 Perl 程序员所期望的那样工作,所以我认为它非常值得推荐(另外,我相信它可能很快就会退出实验状态)。【参考方案2】:
请调查以下代码。
原始代码只需要一点点“爱”。
您应该使用>>
而不是>
,因为最后一个会覆盖每个sub
调用
为调试目的在消息中添加时间戳很有用
使用退出代码 0
指示程序成功完成,并使用某些特定错误代码指示错误
注意:始终在您的代码中包含use strict;
和use warnings;
,这将帮助您避免代码中的许多陷阱。当您执行可能导致错误或潜在意外结果的操作时,Perl 会警告您。
注意:通过添加$filename
作为参数来增加代码片段的子程序可重用性,使用相同的子程序代码在不同的文件中写入消息(有时对于调试目的非常有用)
use strict;
use warnings;
use feature 'say';
my $filename = 'my_prog.log';
my $msg;
$msg = 'INFO: my_prog is started';
logger($filename,$msg);
$msg = 'INFO: my_prog is running';
logger($filename,$msg);
$msg = 'ERROR: my_prog immitage some error';
logger($filename,$msg);
$msg = 'INFO: my_prog is done';
logger($filename,$msg);
exit 0;
sub logger
my $file = shift;
my $msg = shift;
open my $fh, '>>', $file
or die "Couldn't open $file";
say $fh join(' ', scalar localtime, $msg);
close $fh;
产生输出
Mon May 24 01:23:19 2021 INFO: my_prog is started
Mon May 24 01:23:19 2021 INFO: my_prog is running
Mon May 24 01:23:19 2021 ERROR: my_prog immitage some error
Mon May 24 01:23:19 2021 INFO: my_prog is done
参考:open,say
【讨论】:
【参考方案3】:以下是一些应该使它起作用的更改:
my $message_file = 'some_file';
sub filemessage # sub is spelled with a lowercase 's'
my ($arg1) = @_; # args are passed through the array @_
open(my $fh, '>', $message_file) or die "Error: $!"; # declare my $fh
print $fh "$arg1\n"; # \ not /
close $fh;
注意:>
模式将截断文件,因此文件中最多只有 一个 消息。如果要追加到文件,请使用模式>>
。
【讨论】:
哦,你想要>>
。您可能还想提醒所有这些打开+关闭,使用冲洗代替。
@ikegami ">>" - 我不确定 OP 是否希望在文件中添加一条消息或追加。我将把它留给 OP,但添加了一条注释。
参数传递给$j
?不应该是$_[j]
吗?
Args not 以$1
、$2
等形式传递。
代码没有做它声称的; $_[0]
应该在那里而不是 $1
。 (或shift
)以上是关于Perl 将变量传递给子程序的主要内容,如果未能解决你的问题,请参考以下文章