我在主文件夹中有100个子文件夹。他们有不同的名字。每个子文件夹都包含一个.txt文件,该文件有10列。我想为每个子文件夹获取一个新的.txt文件。每个新的.txt文件都必须位于自己的文件夹中。那就是我在每个子文件夹中都会有2个.txt文件(旧的和新的)。我正在尝试选择起始线#34; ATOM"以及每个.txt文件中的一些列2,6,7和8。我的代码如下。它没有正常工作。它不会创建新的.txt文件。我怎么能弄清楚这个问题呢?
#!/usr/bin/perl
$search_text = "ATOM";
@files = <*/*.txt>;
foreach $file (@files) {
print $file . "\n";
open(DATA, $file);
open(OUT_FILE, ">$file a.txt");
while ($line = <DATA>)
{
@fields = split /\s+/, $line;
if ($line =~ m/$search_text/)
{
print OUT_FILE "$fields[2]\t$fields[6]\t$fields[7]\t$fields[8]\n";
}
}
}
close(OUT_FILE);
答案 0 :(得分:1)
要将输出文件a.txt
放入与输入文件相同的目录中,您需要从输入文件名中提取目录名,并将其添加到输出文件名(a.txt
)之前。有几种方法可以做到这一点;最简单的方法是使用标准模块File::Basename中的dirname()
:
use File::Basename;
my $dir = dirname($file);
open(OUT_FILE, ">", "$dir/a.txt") or die "Failed to open $dir/a.txt: $!";
或者您可以直接使用File::Spec:
use File::Spec;
my ($volume, $dir) = File::Spec->splitpath($file);
my $outname = File::Spec->catpath($volume, $dir, 'a.txt');
open(OUT_FILE, ">", $outname) or die "Failed to open $outname: $!";
或者你可以使用regexp substitution:
my $outname = ( $file =~ s![^/]+$!a.txt!r );
open(OUT_FILE, ">", $outname) or die "Failed to open $outname: $!";
Ps。无论如何,我建议采用一些有助于编写更好的Perl脚本的好习惯:
始终使用use strict;
和use warnings;
启动您的脚本。修复他们产生的任何错误和警告。特别是,使用my
声明所有局部变量,使它们具有词汇范围。
检查open()
等函数的返回值,如果失败则中止脚本。 (我在上面的例子中做过这个。)
使用open()
的三参数形式,正如我在上面的示例中所做的那样。如果你的文件名包含有趣的字符,那么破解的可能性要小得多。
考虑使用词法范围的文件句柄(open my $out_file, ...
)而不是全局文件句柄(open OUT_FILE, ...
)。我在上面的代码片段中没有这样做,因为我想让它们与你的其余代码保持兼容,但这是一个很好的做法。
如果您预先声明正则表达式,例如$search_text
,请使用qr//
而不是普通字符串,如下所示:
my $search_text = qr/ATOM/;
效率稍高,特殊字符的引用规则更加明智。
要从数组中打印多个列,请考虑使用join()
和列表切片,如:
print OUT_FILE join("\t", @fields[2,6,7,8]), "\n";
最后,如果我是你,我会重新考虑我的文件命名方案:输出文件名a.txt
与您输入的文件名glob *.txt
匹配,因此如果您运行它,您的脚本可能会中断连续两次。