Perlの複数のフィールドに基づいて行を抽出する方法

Perlの複数のフィールドに基づいて行を抽出する方法

Perlの複数のフィールドに基づいて行を抽出する方法

次のファイルがあります:file1.txtそして、複数のフィールドの複合一致に基づいて行を抽出しようとしています。つまり、行にこれらすべてのフィールドの組み合わせのみが含まれている場合は、これらのフィールドを含む行を抽出する必要があります。

tcp
10.11.38.224
10.185.34.240
9012

ファイル1.txt

access firewall udp 10.14.90.111 240.230.111.222 10.13.45.21 255.255.230.240 eq 8443
access firewall tcp 10.11.38.224 255.233.212.111 10.185.34.240 244.255.240.211 eq 9012
#!/usr/bin/perl

open(SOURCE,"<file1.txt");
while (my @gitLines_mst = <SOURCE>)
{
my $fld0 = "tcp";
my $sIP = "10.11.38.224";
my $dIP = "10.185.34.240";
my $fld5 = "9012";
print "$fld0";
my @llll = grep {"/$fld0/" && "/$sIP/" && "/$dIP/" && "/$fld5"} @gitLines_mst;
print "here please: @llll \n";
}

私はファイルの内容全体と一致する行を再リストする上記のスクリプトを書きました。

私の結果:

access firewall udp 10.14.90.111 240.230.111.222 10.13.45.21 255.255.230.240 eq 8443
access firewall tcp 10.11.38.224 255.233.212.111 10.185.34.240 244.255.240.211 eq 9012

検索しようとしたときに二重引用符も削除しました。

my @llll = grep {/$fld0/ && /$sIP/ && /$dIP/ && /$fld5} @gitLines_mst;

エラーが発生します。

Search pattern not terminated at ./sample line 11.

私が望む出力は次のとおりです。

access firewall tcp 10.11.38.224 255.233.212.111 10.185.34.240 244.255.240.211 eq 9012

ベストアンサー1

#!/usr/bin/perl

while(<>) {
  @F = split;  # split input line into array @F using whitespace as separator.
  # Note: perl arrays start from 0, not 1.

  print if (($F[2] eq 'tcp') && 
            ($F[3] eq '10.11.38.224') &&
            ($F[5] eq '10.185.34.240') &&
            ($F[8] == 9012))
}

ifステートメントは1行にすべて書くことができますが、この形式は読みやすくなります)

たとえば、次のようにmyscript.pl実行可能に保存しますchmod +x myscript.pl

$ ./myscript.pl file1.txt 
access firewall tcp 10.11.38.224 255.233.212.111 10.185.34.240 244.255.240.211 eq 9012

ただし、このプログラムはあまり役に立ちません。実際には、4つの検索基準のすべてに正確に一致する行を印刷する1つの操作のみが実行されます。

注:通常、このようなプログラムの場合はフィルタで書くことをお勧めします。つまり、特定のファイル名をプログラムにハードコードするのではなく、標準入力および/またはコマンドラインに記載されているファイル名から入力を取得します。

この方法では、任意のファイル名に使用でき、他のプログラムの入力またはgrep出力を取得することもできます。awk

Perlのファイルハンドルは<>すぐにこれを行います。標準入力から入力を受け取ります。そしてコマンドラインに引数として指定されたファイル名(存在する場合)。 while (<>) { ...code... }標準入力および/またはファイル入力の検索、フォーマット変更、データ抽出、およびその他の操作を実行するPerlプログラムでよく見られます。


昨日の同様の質問によると、単に配列ではなく意味のある名前を持つ変数が必要な場合は、@F次のように書くことができます。

#!/usr/bin/perl

while(<>) {
  my ($access, $something, $proto, $srcIP, $srcmask,
      $destIP, $destmask, $eq, $port) = split;

  print if (($proto  eq 'tcp') && 
            ($srcIP  eq '10.11.38.224') &&
            ($destIP eq '10.185.34.240') &&
            ($port   == 9012))
}

undef興味がなく、使用する予定がないすべての分野で使用できます。例えば

  my (undef, undef, $proto, $srcIP, undef, $destIP, undef, undef, $port) = split;

ところで、このような作業も簡単に行えますawk

$ awk '$3=="tcp" && $4=="10.11.38.224" && $6=="10.185.34.240" && $9==9012' file1.txt 
access firewall 1 10.11.38.224 255.233.212.111 1 244.255.240.211 eq 9012

またはパールラインで:

$ perl -lane 'print if $F[2] eq "tcp" && $F[3] eq "10.11.38.224" && $F[5] eq "10.185.34.240" && $F[8] == 9012' file1.txt 
access firewall tcp 10.11.38.224 255.233.212.111 10.185.34.240 244.255.240.211 eq 9012

おすすめ記事