如何使用perl在每个不同的子文件夹中获取不同的命名文本文件?

时间:2014-12-21 04:28:10

标签: perl

我在主文件夹中有九个子文件夹。每个子文件夹都包含一个.pdb文件,该文件有10列。我想为每个子文件夹获取一个新的.log文件。每个新的.log文件都必须位于自己的文件夹中。我试图在每个子文件夹中创建一个不同的命名.log文件(如1.log,2.log,3.log ...)。但是我在每个文件夹中都有两个.log文件。如何在每个子文件夹中获得不同的命名.log文件?

.pdb文件:

ATOM      1  O   LIG A   1      -4.657  -0.947  -1.014  1.00  0.00           O  
ATOM      2  N   LIG A   1      -0.173   0.679   0.052  1.00  0.00           N1+
ATOM      3  N   LIG A   1       3.135  -0.678  -0.977  1.00  0.00           N  
ATOM      4  N   LIG A   1       3.331   0.341   1.198  1.00  0.00           N  
ATOM      5  N   LIG A   1       1.046  -0.695  -2.103  1.00  0.00           N  
ATOM      6  C   LIG A   1      -1.086  -0.167   0.546  1.00  0.00           C  
ATOM      7  C   LIG A   1      -2.430   0.177   0.537  1.00  0.00           C  
ATOM      8  C   LIG A   1      -3.476  -0.737   1.080  1.00  0.00           C  
ATOM      9  C   LIG A   1       1.209   0.327   0.061  1.00  0.00           C 
ATOM     10  C   LIG A   1      -2.803   1.409   0.008  1.00  0.00           C  

.log文件:

O   -4.657  -0.947  -1.014
N   -0.173  0.679   0.052
N   3.135   -0.678  -0.977
N   3.331   0.341   1.198
N   1.046   -0.695  -2.103
C   -1.086  -0.167  0.546
C   -2.430  0.177   0.537
C   -3.476  -0.737  1.080
C   1.209   0.327   0.061
C   -2.803  1.409   0.008

我的代码:

#!/usr/bin/perl

use strict;
use warnings;

use File::Basename;


my $search_text = qr/ATOM/;

my @fullpath= <*/*.pdb>;

foreach my $file (@fullpath) {
    print $file . "\n";

    my $dir = dirname($file);

    for (my $i=1; $i < 10; $i++) {
        open(DATA, $file);      
        open(out_file, ">", "$dir/$i.log") or die "Failed to open $dir/$i.log: $!";
    }

    while (my $line = <DATA>) {
        my @fields = split /\s+/, $line;
        if ($line =~ m/$search_text/) { 
            print out_file join("\t", @fields[2,6,7,8]), "\n";
        }
    }
}
close(out_file);

1 个答案:

答案 0 :(得分:1)

主要问题是你有一个内部foreach循环打开输入文件九次($i是1 .. 9因为< 10标准)和九个不同的输出文件,这发生在找到的每个 .pdb文件中。

您需要一个文件范围的计数器,以确保以不同的方式命名每个日志文件。

您可能还会发现考虑这些要点很有用

  • 最好尽可能限制外部模块的导入列表。默认情况下,File::Basename导出fileparsefileparse_set_fstypebasenamedirname。你只想要其中一个,所以你应该写

    use File::Basename qw/ dirname /
    
  • 我已经提到过这个循环

    for (my $i=1; $i < 10; $i++) { ... }
    

    但另外你应该记住,大多数有成就的Perl程序员使用for代替foreach来减少噪音(除了拼写之外,它们在各方面都是相同的)。如果您想要的只是一系列数字,那么您应该使用范围运算符,就像这样

    for my $i (1 .. 9) { ... }
    

    C风格的循环非常罕见。

  • 您不应该使用DATA文件句柄,因为它具有内置目的。实际上你应该在任何地方使用词法文件句柄,比如这个

    open my $out_file, '>', "$dir/$i.log"
    

    但是选择open

  • 的三参数形式做得很好
  • 如果您的处理简单明了,那么最好让<>运算符执行将每行放入$_的默认行为。这使chompsplitprint,正则表达式匹配,以及其他更简洁,因此更具可读性。

我相信这个程序可以满足您的需求。

#!/usr/bin/perl

use strict;
use warnings;

use File::Basename qw/ dirname /;

my $search_text = qr/ATOM/;

my $infile_number;

while (my $infile = glob '*/*.pdb') {

    ++$infile_number;
    my $dir = dirname($infile);
    my $outfile = "$dir/$infile_number.log";
    print "$infile => $outfile\n";

    open my $in_fh,  '<', $infile  or die qq{Failed to open "$infile" for writing: $!};
    open my $out_fh, '>', $outfile or die qq{Failed to open "$outfile" for writing: $!};

    while (<$in_fh>) {
      next unless /$search_text/;
      my @fields = split;
      print $out_fh join("\t", @fields[2,6,7,8]), "\n";
    }
}

<强>更新

  

&#34;日志文件中的列不像.pdb文件中的列那样排序。 .log文件中十进制数的点/点不像.pdb文件那样在顶部和底部。当减号和加十进制数位于顶部和底部时会出现此问题。&#34;

我认为您的意思是小数点在同一列中没有对齐。我的原始程序的这个变体将解决这个问题。但是你确定要在列之间使用制表符吗?通常使用选项卡,以便计算机可以正确地分隔列,并且在用于阅读的文档中没有太多用途。

use strict;
use warnings;

use File::Basename qw/ dirname /;
use Scalar::Util qw/ looks_like_number /;

my $search_text = qr/ATOM/;

my $infile_number;

while (my $infile = glob '*/*.pdb') {

    ++$infile_number;
    my $dir = dirname($infile);
    my $outfile = "$dir/$infile_number.log";
    print "$infile => $outfile\n";

    open my $in_fh,  '<', $infile  or die qq{Failed to open "$infile" for writing: $!};
    open my $out_fh, '>', $outfile or die qq{Failed to open "$outfile" for writing: $!};

    while (<$in_fh>) {
      next unless /$search_text/;
      my @fields = split;
      for (@fields) {
        $_ = sprintf '%6.3f', $_ if looks_like_number($_);
      }
      print $out_fh join("\t", @fields[2,6,7,8]), "\n";
    }
}

<强>输出

O   -4.657  -0.947  -1.014
N   -0.173   0.679   0.052
N    3.135  -0.678  -0.977
N    3.331   0.341   1.198
N    1.046  -0.695  -2.103
C   -1.086  -0.167   0.546
C   -2.430   0.177   0.537
C   -3.476  -0.737   1.080
C    1.209   0.327   0.061
C   -2.803   1.409   0.008