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 将变量传递给子程序的主要内容,如果未能解决你的问题,请参考以下文章

如何将哈希传递给 Perl 中的函数?

perl 子程序参数列表 - “通过别名传递”?

Perl 将字符串识别为标量变量

如何在 C 中打开数据库句柄并使用 SWIG 将其传递给 Perl?

如何将环境变量传递给前端 Web 应用程序?

如何将变量传递给驱动程序执行脚本?