我正在编写从日志文件中提取所有IP地址的代码。 (日志文件包含域名,IP地址和MAC地址列表。)这是我的代码:
npm install --only=prod
问题是每个IP地址打印5次。输出如下:
open(CONF, '<', 'dhcpd.conf') or die "\n";
my @ip;
while(my $line = <CONF> ) {
if ( $line =~ /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/ ) {
@ip = $1;
}
print "@ip,\n";
}
close CONF;
问题出在10.0.0.158
10.0.0.158
10.0.0.158
10.0.0.158
10.0.0.158
10.0.0.159
10.0.0.159
10.0.0.159
10.0.0.159
10.0.0.159
...
,还是在其他地方?
答案 0 :(得分:2)
你有几个问题,但主要的问题似乎是打印@ip
的内容,无论该行是否匹配。如果您只是想将脚本用作过滤器并在找到它们时打印IP地址,那么这是表达它的更好方式:
perl -ne 'print "$1\n" if /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/' dhcpd.conf
或者不是单行的等效代码:
use strict;
use warnings;
while (<>) {
next unless /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/;
print "$1\n";
}
你会像这样跑:
$ perl script.pl dhcpd.conf
如果您想要保存您找到的每个IP地址并在以后使用它们执行某些操作,则需要push到阵列上:
my @ips;
while (<>) {
next unless /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/;
push(@ips, $1);
}
# doing something else...
for (@ips) {
print "$_\n";
}
如果您只想在整个文件中使用唯一的IP地址,则可以使用hash:
my %ips;
while (<>) {
next unless /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/;
$ips{$1} = 1;
}
for (keys(%ips)) {
print "$_\n";
}
答案 1 :(得分:0)
不太确定为什么使用数组(@ip
)来存储标量,输出(没有尾随,
)与您的脚本不匹配,但是它多次出现的原因很可能是因为它在日志文件中多次出现。
如果您想跳过同一地址的连续出现,您需要记住上次看到的地址,而不是显示与上次看到的IP地址相匹配的任何IP地址。
如果您只想显示任何一个IP地址,则需要将所有地址存储在哈希(作为键)中,然后枚举哈希的键。或者只是使用哈希来记住你已经看过(并打印过)的IP。
答案 2 :(得分:0)
这可能是因为这些IP在日志中不止一次显示,所以这是预期的。
如果您是从命令行执行此操作,例如标准Apache日志,您将获得类似的输出:
cat log | awk '{print $1}' | sort | sort -nr -k 1 | head
这不是很整洁,但出于演示目的,您可以在各种类型之间使用uniq来删除重复项。你需要做类似的事情。
有一个模块https://metacpan.org/pod/List::MoreUtils可以轻松完成此任务:
use List::MoreUtils qw(uniq);
my @ip = qw(ip1 ip2 ip3);
my @ip = uniq @ip;
如果您不想使用该模块,可以创建一个子类:
sub uniq {
my %seen;
grep !$seen{$_}++, @_;
}
my @ip = qw(ip1 ip2 ip3);
my @ip = uniq(@ip);
有关这两种方法的详细信息,请参阅perlfaq4。
答案 3 :(得分:-1)
使用Hash而不是Array,请尝试以下代码:
my $ips;
open(CONF, '<', 'dhcpd.conf') or die "Error: $!";
while(my $line = <CONF> ) {
if ( $line =~ /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/ ) {
$ips->{$1} = 1;
}
}
close CONF;
my $all_ips =join("\n", keys %{$ips});
print $all_ips;