【问题标题】:Perl Passing Variable to subroutinesPerl 将变量传递给子程序
【发布时间】: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")

【问题讨论】:

    标签: perl scripting subroutine


    【解决方案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
    

    参考:opensay

    【讨论】:

      【解决方案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
      猜你喜欢
      • 1970-01-01
      • 2021-04-03
      • 1970-01-01
      • 1970-01-01
      • 2017-05-28
      • 2014-12-12
      • 2017-01-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多