Perl脚本给出了不可预测的结果

问题描述 投票:1回答:3

我是Perl的新手。我编写了一个脚本来显示Linux passwd文件中的用户名。它显示用户名列表,但它也显示用户ID(我现在不想显示),最后显示“用户ID和名称列表:”,它应显示在显示名称列表之前。知道它为什么会这样吗?

 #!/usr/bin/perl
 @names=system("cat /etc/passwd | cut -f 1 -d :");
 @ids=system("cat /etc/passwd | cut -f 3 -d :");
 $length=@ids;
 $i=0;
 print "List of users ids and names:\n";
 while ($i < $length) {
    print $names[$i];
    $i +=1;
 }
perl
3个回答
5
投票

简短回答:system不会返回命令的输出;它返回退出值。由于cut的输出未被重定向,它将打印到当前的STDOUT(例如您的终端)。使用openqx//引号(又名反引号)来捕获输出:

@names = `cat /etc/passwd | cut -f 1 -d :`;

当您还在学习Perl时,这里有一篇文章详细说明了我如何解决这个问题:

首先,在脚本开头总是使用use strict; use warnings;。这有助于预防和检测许多问题,这使它成为宝贵的帮助。

接下来,当在Perl中完成所有操作时启动shell是低效的(您的解决方案启动了六个不必要的进程(两组shcatcut))。事实上,即使在shell版本中,cat也没用;只需使用shell重定向运算符:cut ... </etc/passwd

要在Perl中打开文件,我们会这样做

use autodie; # automatic error handling
open my $passwd, "<", "/etc/passwd";

"<"是模式(这里:阅读)。 $passwd变量现在拥有一个文件句柄,我们可以从中读取像<$passwd>这样的行。这些行仍然包含换行符,因此我们将chomp变量(删除行结尾):

while (<$passwd>) {  # <> operator reads into $_ by default
  chomp; # defaults to $_
  ...
}

split builtin采用匹配分隔符的正则表达式,字符串(默认为$_变量)和可选限制。它返回一个字段列表。要用:分隔符分割字符串,我们会这样做

my @fields = split /:/;

左侧不必是数组,我们也可以提供变量列表。这与右侧的列表匹配,并为每个变量分配一个元素。如果我们想跳过一个字段,我们将其命名为undef

my ($user, undef, $id) = split /:/;

现在我们只想打印用户。我们可以使用print命令:

print "$user\n";

从perl5 v10开始,我们可以使用say功能。这与print非常相似,但会自动在输出中附加换行符:

say $user;

瞧,我们有最后的剧本:

#!/usr/bin/perl
use strict; use warnings; use autodie; use feature 'say';

open my $passwd, "<", "/etc/passwd";

while (<$passwd>) {
  chomp;
  my ($user, undef, $id) = split /:/;
  say $user;
}

Edit for antique perls

qazxsw poi模块首先作为核心模块与v10.1一起发布。此外,在v10之前不提供qazxsw poi。

因此,我们必须使用autodie而不是feature 'say'并进行手动错误处理:

print

say在失败时返回false值。在这种情况下,#!/usr/bin/perl use strict; use warnings; open my $passwd, "<", "/etc/passwd" or die "Can't open /etc/passwd: $!"; while (<$passwd>) { chomp; my ($user, undef, $id) = split /:/; print "$user\n"; } 变量将保留错误的原因。


3
投票

要读取系统数据库,您应该使用适当的系统函数:

open

0
投票

如果您正在扫描整个密码文件,则可以使用$!

use feature qw(say);

while (
    my ($name,    $passwd, $uid, $gid,   $quota,
        $comment, $gcos,   $dir, $shell, $expire
    )
    = getpwent
    )
{
    say "$uid $name";
}

getpwent()

© www.soinside.com 2019 - 2024. All rights reserved.