简体   繁体   English

Perl使用单个文件打开句柄渲染多个csv文件?

[英]Multiple csv file rendering by Perl using single file open handle?

I have this code, where I want to handle multiple csv(currently its just one file) file and use perl to render its format before its shipped to a linux-box and replaces original file content using ssh connection. 我有这段代码,我想在其中处理多个csv(当前仅为一个文件)文件,并在将其运送到linux-box之前使用perl呈现其格式,并使用ssh连接替换原始文件内容。 Here is the code 这是代码

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

What I'm interested to know and perhaps get some help from perl programmer that using one file handle can I open multiple files eg In my case I have something like this 我有兴趣了解的东西,也许从perl程序员那里得到了一些帮助,即使用一个文件句柄可以打开多个文件,例如,在我的情况下,我有类似的东西

  1. virus.csv virus.csv
  2. bot.csv bot.csv
  3. malware.csv malware.csv

Do i need to re-copy for loop code for each csv file with a different handle? 我是否需要为具有不同句柄的每个csv文件重新复制循环代码? The destination file remotenet.conf remains the same. 目标文件remotenet.conf保持不变。

After correct rendering of for eg one csv file the remotenet.conf on web-ui would look something like 正确渲染一个csv文件后,web-ui上的remotenet.conf看起来像

Virus
    10.10.2.1
     .......

Bot
    10.10.4.1
     ......

It would be great that multiple changes happen in one-go, with just one auto-deploy(see code at end). 一次只进行一次自动部署就可以进行多次更改,这将是很棒的选择(请参阅最后的代码)。 I hope I'm able to understand the problem. 我希望我能理解这个问题。 Please let me know if more clarification is required. 请让我知道是否需要进一步说明。

thanks 谢谢

WHAT I WANT TO ACCOMPLISH 我要完成的事情

I want a dynamic code, where there are multiple csv ready for rendering kept inside one folder. 我想要一个动态代码,其中有多个准备用于呈现的csv保存在一个文件夹中。 The sequence is described as :- 序列描述为:

  1. read each csv file from folder. 从文件夹读取每个csv文件。
  2. converts it into the acceptable format. 将其转换为可接受的格式。
  3. Change two variables values based upon csv file name. 根据csv文件名更改两个变量值。 For eg 例如

For filename malware.csv 对于文件名恶意软件.csv

my $source = 'BAD-IP-Addresses-LABEL'; 我的$ source ='BAD-IP-Addresses-LABEL'; my $type_description = 'honeypots-for-examnple'; 我的$ type_description ='蜜罐为例';

For bot.csv 对于bot.csv

my $source = 'bot-net'; 我的$ source ='bot-net'; my $type_description = 'top-10'; 我的$ type_description ='top-10';

At end, copies the formated file along with contents into remotenet.conf through ssh. 最后,通过ssh将格式化的文件及其内容复制到remotenet.conf中。

You cannot read from a file opened in append >> mode. 您无法读取以append >>模式打开的文件。 It seems you've just renamed the OUT filehandle to FP , but that isn't enough. 看来您刚刚将OUT文件句柄重命名为FP ,但这还不够。

  • The original code included a chdir $seculert_dir – this makes sense because now we don't have to prefix our filenames with the directory all the time (it's the equivalent to the cd command in the shell). 原始代码包含一个chdir $seculert_dir –这很有意义,因为现在我们不必一直在文件名前加上目录前缀(这等效于Shell中的cd命令)。
  • The original code didn't exactly use best practices. 原始代码未完全使用最佳实践。 I wrapped the scp and ssh commands with versions that do a minimal amount of error checking. 我将scpssh命令包装为进行最少错误检查的版本。
  • It is also unnecessary to invoke external tools for things we can do with Perl. 也不需要为使用Perl可以完成的事情调用外部工具。

Here is my updated code, that can read the data from simplistic CSV files: 这是我更新的代码,可以从简单的CSV文件读取数据:


First, we start the preample. 首先,我们开始预采样。 use warnings is more preferable than the -w switch. 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";

That was our configuration. 那就是我们的配置。 Next we fetch the conf from the server using the wrapped SCP command: 接下来,我们使用包装的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" => '.');

We now open a file where we put our changed configuration 现在,我们打开一个文件,将更改后的配置放入其中

# 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: $!);

Now we open the old configuration, copy it over, but skip lines starting with SECULERT . 现在,我们打开旧配置,将其复制过来,但是跳过以SECULERT开头的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;

Notice how I've used “lexical filoehandles” ( open my $fh, ... ). 请注意,我是如何使用“词汇纤细句柄”的( open my $fh, ... )。 This avoids some problems, and is more modern than using barewords. 这样可以避免一些问题,并且比使用裸字更现代。

Next, we loop through the CSV files. 接下来,我们遍历CSV文件。 We open each one, then extract the 2nd column and print it with the other stuff into the changed configuration file. 我们打开每一列,然后提取第二列,并将其与其他内容一起打印到更改的配置文件中。

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

Now we have all the information we want in the new configuration file and can upload it to the server: 现在,我们在新的配置文件中拥有了所有想要的信息,可以将其上传到服务器:

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';

Next, we run the deploy script: 接下来,我们运行部署脚本:

# 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";

Here are the wrappers for scp and ssh . 这是scpssh的包装。 They are subroutines (functions, procedures, or methods in other languages). 它们是子例程 (其他语言的函数,过程或方法)。 The arguments are in the @_ array from which we unpack them into variables with better names. 参数位于@_数组中,从中将它们解压缩为具有更好名称的变量。 The system command takes a name of a command and a list of arguments. system命令采用命令名称和参数列表。 Because this circumvents the shell, we don't have to think about shell escapes. 因为这绕过了外壳,所以我们不必考虑外壳转义。 system returns zero on sucess, so we use that to check for errors. 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.
}

This code could still be improved, eg by using a proper CSV parser like Text::CSV , using better SSH bindings than simply wrapping command line programs, automated error checking with autodie , and a better handling of tempfiles. 仍然可以改进此代码,例如,通过使用诸如Text::CSV的适当CSV解析器,使用比仅包装命令行程序更好的SSH绑定,使用autodie自动错误检查,以及更好地处理tempfile。

It seems you want different $source values for different files. 看来您想要不同文件的不同$source值。 For this, we should use a more complex data structure than @csv_files – I'd use a hash of arrays, eg 为此,我们应该使用比@csv_files更复杂的数据结构–我将使用数组的哈希,例如

my %csv_files = (
  'malware.csv' => ['BAD-IP-Addresses-LABEL', 'honeypots-for-examnple'],
  'bot.csv'     => ['bot-net', 'top-10'],
);

This is a dictionary that maps keys (here filenames) to values (here the contents of two columns). 这是一个字典,将键(这里是文件名)映射到值(这里是两列的内容)。 Instead of looping over entries in an array, we would now loop over the keys in this hash: 现在,我们无需遍历数组中的条目,而可以遍历此哈希中的键:

for my $csv_file (keys %csv_files) {
  my ($source, $type_description) = @{ $csv_files{$csv_file} };

  ...
}

The expression $csv_files{$csv_file} accesses the entry called $csv_file in the hash $csv_files . 表达式$csv_files{$csv_file}访问哈希$csv_files名为$csv_file的条目。 This entry contains an array reference as value. 此项包含一个数组引用作为值。 The @{…} around that converts the array reference to an array, which we can unpack with a list assignment my ($foo, $bar) = @array . @{…}将数组引用转换为数组,我们可以使用列表分配my ($foo, $bar) = @array解包。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM