数据驱动的Perl脚本

时间:2019-06-24 01:43:58

标签: perl

我想列出目录中的文件n文件夹。这是此目录中文件的列表。

Output1.sv
Output2.sv
Folder1
Folder2
file_a
file_b
file_c.sv

但是其中一些我不希望将其列出。不包含文件的列表,我在input.txt中列出如下。注意:其中一些是文件,一些是文件夹

NOT_INCLUDED=file_a
NOT_INCLUDED=file_b
NOT_INCLUDED=file_c.sv

这是代码。

#!/usr/intel/perl

use strict;
use warnings;

my $input_file    = "INPUT.txt";

open ( OUTPUT, ">OUTPUT.txt" );

file_in_directory();

close OUTPUT;


sub file_in_directory {

   my $path       = "experiment/";

   my @unsort_output;
   my @not_included;
   open ( INFILE, "<", $input_file);
   while (<INFILE>){
      if ( $_ =~ /NOT_INCLUDED/){
          my @file = $_;
          foreach my $file (@file) {
              $file =~ s/NOT_INCLUDED=//;
              push @not_included, $file;
          }
      }
   }
   close INFILE;

   opendir ( DIR, $path ) || die "Error in opening dir $path\n";
   while ( my $filelist = readdir (DIR) ) {
      chomp $filelist;
      next if ( $filelist =~ m/\.list$/ );
      next if ( $filelist =~ m/\.swp$/ );
      next if ( $filelist =~ s/\.//g);
      foreach $_ (@not_included){
         chomp $_;
         my $not_included = "$_";
         if ( $filelist eq $not_included ){
            next;
         }

      push @unsort_output, $filelist;         
    }

   closedir(DIR);

   my @output = sort @unsort_output;
   print OUTPUT @output;   
}

我想要的输出是列出该目录中的所有文件,但input.txt'NOT_INCLUDED'中的文件列表除外。

Output1.sv
Output2.sv
Folder1
Folder2

但是我得到的输出似乎仍然包含该不需要的文件。

2 个答案:

答案 0 :(得分:2)

这部分代码没有意义:

   while ( my $filelist = readdir (DIR) ) {
      ...
      foreach $_ (@not_included){
         chomp $_;
         my $not_included = "$_";
         if ( $filelist eq $not_included ){
            next;
         }  # (1)

      push @unsort_output, $filelist;  # (2)
    }

此代码包含三个大括号({),但仅包含两个大括号(})。如果您尝试按原样运行代码,则它将失败,并显示语法错误。

push行(标记为(2))是foreach循环的一部分,但缩进时好像在外面。要么缩进更多(以与(1)对齐),要么您需要在其前面添加}。两种选择都没有太大意义:

  • 如果pushforeach循环之外,则next语句(以及整个foreach循环)无效。可以删除它。
  • 如果pushforeach循环内,则每个目录条目($filelist)将被多次推送,@not_included中的每一行都会被推送一次(除了在@not_included中某处列出的名称;这些名称将被减少一倍。)

还有其他几个问题。例如:

  • $filelist =~ s/\.//g从文件名中删除所有点,例如file_c.svfile_csv中。这意味着它将永远不会与您的输入文件中的NOT_INCLUDED=file_c.sv相匹配。
  • 更糟糕的是,next if s///部分意味着循环会跳过名称中包含点的所有文件,例如Output1.svOutput2.sv
  • 打印的结果没有分隔符,因此您会得到类似 Folder1Folder1Folder1Folder2Folder2Folder2file_afile_afile_bfile_b中的OUTPUT.txt
  • 无缘无故地使用全局变量,例如INFILEDIR

这是我编写代码的方式:

#!/usr/intel/perl
use strict;
use warnings;

my $input_file = 'INPUT.txt';

my %is_blacklisted;
{
    open my $fh, '<', $input_file or die "$0: $input_file: $!\n";
    while (my $line = readline $fh) {
        chomp $line;
        if ($line =~ s!\ANOT_INCLUDED=!!) {
            $is_blacklisted{$line} = 1;
        }
    }
}

my $path = 'experiment';

my @results;
{
    opendir my $dh, $path or die "$0: $path: $!\n";
    while (my $entry = readdir $dh) {
        next
            if $entry eq '.' || $entry eq '..'
            || $entry =~ /\.list\z/
            || $entry =~ /\.swp\z/
            || $is_blacklisted{$entry};

        push @results, $entry;
    }
}

@results = sort @results;

my $output_file = 'OUTPUT.txt';
{
    open my $fh, '>', $output_file or die "$0: $output_file: $!\n";
    for my $result (@results) {
        print $fh "$result\n";
    }
}

INPUT.txt的内容(更具体地说,NOT_INCLUDED=之后的部分)被读入哈希(%is_blacklisted)中。这样可以轻松查找条目。

然后,我们处理目录条目。我们跳过...(我假设您不想要这些)以及所有以*.list*.swp结尾的文件(在您的原始代码中) 。我们还将跳过所有列入黑名单的文件,即在INPUT.txt中被指定为排除的文件。其余条目收集在@results中。

我们对结果进行排序,并将其写入OUTPUT.txt,每行一个条目。

答案 1 :(得分:1)

这里没有过多偏离您的代码,这是解决方案。请找到评论:

#!/usr/intel/perl
use strict;
use warnings;
my $input_file    = "INPUT.txt";
open ( OUTPUT, ">OUTPUT.txt" );
file_in_directory();
close OUTPUT;

sub file_in_directory {
    my $path       = "experiment/";
    my @unsort_output;
    my %not_included; # creating hash map insted of array for cleaner and faster implementaion.
    open ( INFILE, "<", $input_file);
    while (my $file = <INFILE>) {
        if ($file =~ /NOT_INCLUDED/) {
            $file =~ s/NOT_INCLUDED=//;
            $not_included{$file}++; # create a quick hash map of (filename => 1, filename2 => 1)
        }
    }
    close INFILE;
    opendir ( DIR, $path ) || die "Error in opening dir $path\n";
    while ( my $filelist = readdir (DIR) ) {
        next if $filelist =~ /^\.\.?$/xms; # discard . and .. files
        chomp $filelist;
        next if ( $filelist =~ m/\.list$/ );
        next if ( $filelist =~ m/\.swp$/ );
        next if ( $filelist =~ s/\.//g);
        if (defined $not_included{$filelist}) {
            next;
        }
        else {
            push @unsort_output, $filelist;
        }
    }
    closedir(DIR);  # earlier the closedir was inside of while loop. Which is wrong.
    my @output = sort @unsort_output;
    print OUTPUT join "\n", @output;
}