我有这个代码,我想处理多个csv(目前只是一个文件)文件,并使用perl在其发送到linux-box之前呈现其格式,并使用ssh连接替换原始文件内容。这是代码
#!/usr/bin/perl -w
use strict;
# this is a csv which will contains IP addresses of one specific category for e.g malware.
my $seculert_qradar_list = "$seculert_dir/seculert.csv";
#ssh connection information
my $qradar_console = '10.10.1.22';
my $qradar_ssh_key = "$seculert_dir/qr-id_dsa";
my $qradar_ssh_knownhosts = "$seculert_dir/known_hosts";
#################################################################################
# NOTE: this is the "OUT" file.
# 1 - Name
# 2 - Sub-Name
# 3 - IP Address
# 4 - is colour, deprecated
# 5 - database length, deprecated
# 6 - asset weight, deprecated
# 7 - an ID for the 'record' each unique name pair (first 2 columns) gets an ID
#################################################################################
my $source = 'BAD-IP-Addresses-LABEL';
my $type_description = 'honeypots-for-examnple';
# Based upon the format described above I want to render the csv as written in print OUT statement. This format is important, because the endsystem process the file (remotenet.conf) based upon the provided layout.
open(FP, ">>$seculert_qradar_list");
for my $line (<FP>) {
my ($hostname, $ip, $something1, $something2) = split(/,/, $line);
print OUT "$source $type_description $ip #FF0000 0 90 29\n";
}
close(FP);
# Here I just want the contents of modified csv to be written over remotenet.conf. This file is then processed through auto-deploy script by the system. The results get populated on front-end webserver.
print "Sending to QRadar...\n";
# SSH To QRadar's Console and push out file + trigger update
`scp -i $qradar_ssh_key -o UserKnownHostsFile=$qradar_ssh_knownhosts -o StrictHostKeyChecking=no root\@$qradar_console:/store/configservices/staging/globalconfig/remotenet.conf .`;
`sed -i -e '/^SECULERT/d' remotenet.conf`;
`cat $seculert_qradar_list >> remotenet.conf`;
`scp -i $qradar_ssh_key -o UserKnownHostsFile=$qradar_ssh_knownhosts -o StrictHostKeyChecking=no remotenet.conf root\@$qradar_console:/store/configservices/staging/globalconfig/remotenet.conf`;
print "Cleaning up...\n";
# Remove our SECULERT list and the newly pushed out qradar conf
unlink($seculert_qradar_list); unlink ('remotenet.conf');
print "Deploying in QRadar...(takes time to complete)\n";
# QRadar magic
`ssh -i $qradar_ssh_key -o UserKnownHostsFile=$qradar_ssh_knownhosts -o StrictHostKeyChecking=no root\@$qradar_console /opt/qradar/upgrade/util/setup/upgrades/do_deploy.pl`;
print "Complete!\n\n";
我有兴趣知道并且可能从perl程序员那里获得一些使用一个文件句柄的帮助我可以打开多个文件,例如在我的情况下我有这样的东西
我是否需要使用不同的句柄为每个csv文件重新复制循环代码?目标文件remotenet.conf
保持不变。
在正确呈现例如一个csv文件后,web-ui上的remotenet.conf看起来像
Virus
10.10.2.1
.......
Bot
10.10.4.1
......
一次性发生多次变更会很棒,只需一次自动部署(参见最后的代码)。我希望我能理解这个问题。如果需要进一步澄清,请告诉我。
感谢
我想要实现的目标
我想要一个动态代码,其中有多个csv可以保存在一个文件夹中。该序列描述为: -
对于文件名malware.csv
my $ source ='BAD-IP-Addresses-LABEL'; 我的$ type_description ='honeypots-for-examnple';
适用于bot.csv
my $ source ='bot-net'; 我的$ type_description ='top-10';
最后,通过ssh将格式化文件与内容一起复制到remotenet.conf中。
答案 0 :(得分:4)
您无法读取以追加>>
模式打开的文件。您似乎刚刚将OUT
文件句柄重命名为FP
,但这还不够。
chdir $seculert_dir
- 这是有道理的,因为现在我们不必一直为文件名添加前缀(它等同于shell中的cd
命令) scp
和ssh
命令包含在进行最少量错误检查的版本中。这是我的更新代码,可以读取简单CSV文件中的数据:
首先,我们开始预采样。 use warnings
比-w
切换更优选。
#!/usr/bin/perl
use strict;
use warnings;
my $seculert_dir = "!FIXME!";
chdir $seculert_dir; # go into that dir, so that we don't have to use prefixes
my @csv_files = ("seculert.csv"); # this is a csv which will contains IP addresses
# of one specific category for e.g malware.
# We only use the 2nd column
#ssh connection information
my $qradar_console = '10.10.1.22';
my $qradar_ssh_key = "qr-id_dsa";
my $qradar_ssh_knownhosts = "known_hosts";
那是我们的配置。接下来,我们使用包装的SCP命令从服务器获取conf:
# fetch the remotenet.conf from QRadar
print STDERR "Fetching configuration from QRadar...\n";
scp("root\@$qradar_console:/store/configservices/staging/globalconfig/remotenet.conf" => '.');
我们现在打开一个文件,我们将更改后的配置
# write the changed conf here before uploading:
open my $new_conf, ">", "remotenet.conf.changed" or die qq(Can't open "remotenet.conf.changed" for writing: $!);
现在我们打开旧配置,将其复制,但跳过以SECULERT
开头的行。
# copy old conf over, delete lines starting with "SECULERT"
open my $old_conf, "<", "remotenet.conf" or die qq(Can't open "remotenet.conf" for reading: $!);
while (<$old_conf>) {
print {$new_conf} $_ unless /^SECULERT/;
}
close $old_conf;
注意我是如何使用“lexical filoehandles”(open my $fh, ...
)的。这避免了一些问题,并且比使用裸字更现代。
接下来,我们循环访问CSV文件。我们打开每一个,然后提取第二列并将其与其他内容一起打印到更改的配置文件中。
# append the data from the CSVs
for my $csv_file (@csv_files) {
my $source = 'BAD-IP-Addresses-LABEL';
my $type_description = 'honeypots-for-examnple';
open my $csv, "<", $csv_file or die qq(Can't open "$csv_file" for reading: $!);
while (my $line = <$csv>) {
my (undef, $ip) = split /,/, $line; # we're only interested in the 2nd column
# Based upon the format described below I want to render the csv
# as written in print OUT statement. This format is important, because the
# endsystem process the file (remotenet.conf) based upon the provided layout.
#
# Columns in the output:
# 1 - Name
# 2 - Sub-Name
# 3 - IP Address
# 4 - is colour, deprecated
# 5 - database length, deprecated
# 6 - asset weight, deprecated
# 7 - an ID for the 'record' each unique name pair (first 2 columns) gets an ID
print {$new_conf} "$source $type_description $ip #FF0000 0 90 29\n";
}
}
现在我们在新配置文件中拥有了我们想要的所有信息,并可以将其上传到服务器:
close $new_conf;
# copy the changed remotenet.conf back to QRadar
scp('remotenet.conf.changed' => "root\@$qradar_console:/store/configservices/staging/globalconfig/remotenet.conf");
# Remove our SECULERT list and the newly pushed out qradar conf
print STDERR "Cleaning up...\n";
unlink $_ or warn qq(Can't remove "$_": $!) for 'remotenet.conf', 'remotenet.conf.changed';
接下来,我们运行部署脚本:
# QRadar magic -- run deploy script
print STDERR "Deploying in QRadar...(takes time to complete)\n";
ssh("root\@$qradar_console", '/opt/qradar/upgrade/util/setup/upgrades/do_deploy.pl');
print STDERR "Complete!\n\n";
以下是scp
和ssh
的包装器。它们是子例程(其他语言中的函数,过程或方法)。参数位于@_
数组中,我们将它们解压缩为具有更好名称的变量。 system
命令采用命令名称和参数列表。因为这绕过了shell,我们不必考虑shell转义。 system
在成功时返回零,因此我们使用它来检查错误。
# Wrappers for SSH and SCP commands
sub scp {
my ($from, $to) = @_;
my $success = 0 == system 'scp',
'-i' => $qradar_ssh_key,
'-o' => "UserKnownHostsFile=$qradar_ssh_knownhosts",
'-o' => "StrictHostKeyChecking=no",
$from => $to;
return $success if defined wantarray; # return failure when somebody checks for it
die qq(Can't scp "$from" to "$to") if not $success; # die when failure, and nobody checks.
}
sub ssh {
my ($host, $command) = @_;
my $success = 0 == system 'ssh',
'-i' => $qradar_ssh_key,
'-o' => "UserKnownHostsFile=$qradar_ssh_knownhosts",
'-o' => "StrictHostKeyChecking=no",
$host, $command;
return $success if defined wantarray; # return failure when somebody checks for it
die qq(Can't ssh into "$host" for '$command') if not $success; # die when failure, and nobody checks.
}
此代码仍可以改进,例如通过使用适当的CSV解析器(如Text::CSV
),使用更好的SSH绑定,而不仅仅包装命令行程序,使用autodie
自动进行错误检查,以及更好地处理临时文件。
对于不同的文件,您似乎需要不同的$source
值。为此,我们应该使用比@csv_files
更复杂的数据结构 - 我使用数组的散列,例如。
my %csv_files = (
'malware.csv' => ['BAD-IP-Addresses-LABEL', 'honeypots-for-examnple'],
'bot.csv' => ['bot-net', 'top-10'],
);
这是一个将键(这里是文件名)映射到值(这里是两列的内容)的字典。我们现在将循环遍历此哈希中的键,而不是循环遍历数组中的条目:
for my $csv_file (keys %csv_files) {
my ($source, $type_description) = @{ $csv_files{$csv_file} };
...
}
表达式$csv_files{$csv_file}
访问散列$csv_file
中名为$csv_files
的条目。此条目包含数组引用作为值。 @{…}
周围将数组引用转换为数组,我们可以使用列表赋值my ($foo, $bar) = @array
解包。