1

私は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;
 }
4

3 に答える 3

5

簡単な答え:systemコマンドからの出力は返されません。終了値を返します。の出力はcutリダイレクトされないため、現在の STDOUT (端末など) に出力されます。openまたはqx//引用符 (別名バッククォート) を使用して出力をキャプチャします。

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

あなたはまだ Perl を学んでいるので、私がその問題を解決する方法を詳しく説明した記事を以下に示します。

まず、常にuse strict; use warnings;スクリプトの先頭に。これは、多くの問題を防止および検出するのに役立ち、非常に役立ちます。

次に、すべてを Perl 内で実行できる場合にシェルを開始するのは非効率的です (ソリューションは 6 つの不要なプロセス ( shcat、の 2 つのセットcut) を開始します)。実はcatシェル版でもだめなのです。シェルリダイレクト演算子を使用するだけです: 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区切り記号、文字列 (デフォルトは$_変数)、およびオプションの制限に一致する正規表現を取ります。フィールドのリストを返します。文字列を:セパレータで分割するには、次のようにします

my @fields = split /:/;

左辺は配列である必要はありません。変数のリストを指定することもできます。これは右側のリストと一致し、各変数に 1 つの要素を割り当てます。フィールドをスキップしたい場合は、次のように名前を付けます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;
}

アンティークパールの編集

このautodieモジュールは、v10.1 でコア モジュールとして配布されました。また、feature 'say'v10 より前では使用できません。

したがって、print代わりに使用sayして、手動のエラー処理を行う必要があります。

#!/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";
}

openは、失敗すると false の値を返します。その場合、$!変数はエラーの理由を保持します。

于 2013-07-20T19:30:34.130 に答える
3

システム データベースの読み取りには、適切なシステム関数を使用する必要があります。

use feature qw(say);

while (
    my ($name,    $passwd, $uid, $gid,   $quota,
        $comment, $gcos,   $dir, $shell, $expire
    )
    = getpwent
    )
{
    say "$uid $name";
}
于 2013-07-20T20:42:50.720 に答える
0

パスワード ファイル全体をスキャンする場合は、次を使用できますgetpwent()

while( my @pw = getpwent() ){
  print "@pw\n";
}

を参照してくださいperldoc -f getpwent

于 2013-07-20T20:50:30.547 に答える