perl 处理命令行参数 - @ARGV

使用任何Perl脚本,用户不仅可以通过命令行运行程序,还可以传递'perl program_name.pl -a --machine remote / etc等参数。作为作者,您可以使用@ARGV数组来查看传递了哪些值。这是由Perl自动提供的,不必声明。

argv.pl
# Example:
# Simple program called programming.pl
use strict;
use warnings;
use Data::Dumper qw(Dumper);

print Dumper \@ARGV;

# Run the program like this: perl programming.pl -a --machine remote /etc
# The output would be:
$VAR1 = [ '-a',
          '--machine',
          'remote',
          '/etc'
        ];

\!h # Extract command line arguments from @ARGV

# @ARGV is where the diamond operator looks when called, trying to determine what filenames it should use.
# Because of how it works, you have a chance to tinker with it and force specific files, regardless of what the user chose on the command line.
# Example:
@ARGV = qw(larry moe curly); # force these three files to be read
while (<>) {
  chomp;
  say "It was $_ that I saw in some stooge-like file!";
}

perl 双钻石操作员

对于特殊字符,常规钻石存在问题,在v5.22中使用双钻石修复。它与常规钻石操作员完全相同,只是没有运行外部程序的魔力。

double_diamond.pl
\!h use v5.22;

while (<<>>) {
  chomp;
  say "It was $_ that I saw!";
}

perl 钻石运营商

这可以被认为是一种特殊的线输入算子。但它不是从键盘获取输入,而是来自用户的输入选择。钻石操作员几乎专门用于while循环。具体来说,它允许我们迭代命令行上给出的所有文件中的行。

diamond_operator.pl
while (defined($line = <>)) {
  chomp($line);
  say "It was $line that I saw!";
}

# There's also a shortcut for this:
while (<>) {
  chomp; # acts on $_ by default
  say "It was $_ that I saw!";
}

# So, if your arguments are fred, barney and betty, the program will return something like:
# "It was [a line from file fred] that I saw!";
# "It was [another line from file fred] that I saw!";
# ...until it reaches the end of file fred.
# Then it moves onto files barney and betty, doing the same thing.
# The current file's name is stored in $ARGV, it could be '-' if its a standard input stream.
# Note: there's no break when you go from one file to another, 
# as if the input files merged into one big one.

perl 掉出循环

当你到达文件结尾时,行输入操作符<STDIN>将返回undef,这对于丢弃循环非常方便。

dropping_out_of_loops.pl
while (defined($line = <STDIN>)) { # reading input into a variable and checking if it's defined.
  print "I saw $line"; # if it is, you're running the body of the while loop and printing each line.
}

# foreach alternative:
foreach(<STDIN>) {
  print "I saw $_";
}

# The differnence between the two is how they work through the input behind the scenes.
# The while loop, Perl reads a single line of input, puts it into a variable and runs the body of the loop.
# In a foreach loop, it reads all of the input before the loop can start running, this can become problematic with big web server logfiles.
# Therefore, it's usually better to use the while loop's shortcut.

perl 具有状态的持久私有变量

使用'my',您可以在子例程中将变量设置为私有,但每次调用子例程时都必须再次定义变量。州修复了这种不便,使变量变为私有,但也在调用之间保留了它们的值。

state.pl
sub marine {
  state $n = 0; # private, persistent variable $n
  $n += 1;
  say "Hello, sailor number $n!";
}
# state isn't just used for scalar variables. 
# However, you can't initialize arrays and hashes in list context with state:
state @numbers; # OK
state @numbers = qw(...); # WRONG, won't work

perl 从子程序中省略&符号

当您不必在子调用上添加&符号时,有一个通用规则。如果编译器在调用之前看到子例程定义,或者Perl可以从语法中判断它是子例程,则可以在没有&符号的情况下调用它。

omit_ampersand.pl
# Except for the main rules, your parameter list needs to be in parentheses, it's got to be a function call:
my @cards = shuffle(@deck_of_cards); # no ampersand needed on &shuffle

# However, if Perl's internal compiler has already seen the subroutine definition,
# you can even omit the parentheses around the argument list:
sub division {
  $_[0] / $_[1]; # divide first param by second
}

my $quotient = division 355, 113; # uses &division
# the sub declaration has to be placed before the invocation

\!h # Important - you cannot omit the ampersand if your sub has the same name as a Perl built-in:
sub chomp {
  say "Munch, munch!";
}

&chomp; # ampersand not optional here

perl 返回运算符

这用于在完成任何后续进程之前立即停止程序。

return.pl
my @names = qw/ fred barney betty dino wilma pebbles bamm-bamm/;
my $result = &which_element_is("dino", @names);

# Find the index of dino, in the array @names
sub which_element_is {
  my($what, @array) = @_; # $what = to look for, @array = to search in
  foreach (0..$#array) { # iterate all indices of @array
    if ($what eq $array[$_]) {
      return $_; # return early once found
    }
  }
  -1             # element not found - 'value not found' code (return not needed here)
}

perl 高水位算法+空参数

洪水过后,当水流最后一次飙升并退去时,高水位标记显示最高水位。这个子程序跟踪那个高水位线,这是迄今为止最大的数字。

high_water_mark.pl
$maximum = &max(3, 5, 10, 4, 6);

sub max {
  my($max_so_far) = shift @_; # takes first element from parameter array
  foreach (@_) { # iterate through remaining values in the array
    if ($_ > $max_so_far) { # if current number is bigger than current max,
      $max_so_far = $_; # set the current number to the current max instead
    }
  }
  $max_so_far; # return value
}

\!h # Empty Parameter Lists
# This comes into play with a line like this:
$maximum = &max(@numbers);
# @numbers might sometimes be an empty list
# Firstly, the subroutine sets $max_so_far by unshifting @_, making it undef.
# Then, the foreach loops tries to iterate over @_, executing the loop body zero times as @_ is empty.
# In the end, Perl returns the value of $max_so_far, undef, as the return value.

perl 子程序中的私有变量

默认情况下,Perl中的所有变量都是全局变量。但是,您可以使用my运算符创建自己的称为词法变量的私有变量。

private_variables.pl
sub max {
  my($m, $n); # new, private variables for this block
  ($m, $n) = @_; # give names to parameters
  if ($m > $n) {$m} else {$n}
  
  # the second line can be omitted and merged with the first one like so:
  # my ($m, $n) = @_; 
}

# Note: without the parentheses, my only declares a single lexical variable:
my $fred, $barney; # failed to declare $barney
my ($fred, $barney); # correct, declared both

perl 强制标量上下文

有时,您可能需要强制标量上下文,其中Perl期望列表。假函数'标量'用于此。

force_scalar.pl
@rocks = qw( talc quartz jade obsidian);
print "How many rocks do you have?\n"; 
print "I have ", @rocks, " rocks!\n"; # WRONG, prints names of the rocks
print "I have ", scalar @rocks, " rocks!\n"; # correct, gives number of rocks