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