我在perl脚本中有以下函数:
sub fileSize {
my $file = shift;
my $opt = shift;
open (FILE, $file) or die "Could not open file $file: $!";
$/ = ">";
my $junk = <FILE>;
my $g_size = 0;
while ( my $rec = <FILE> ) {
chomp $rec;
my ($name, @seqLines) = split /\n/, $rec;
my $sec = join('',@seqLines);
$g_size+=length($sec);
if ( $opt == 1 ) {
open TMP, ">>", "tmp" or die "Could not open chr_sizes.log: $!\n";
print TMP "$name\t", length($sec), "\n";
}
}
if ( $opt == 0 ) {
PrintLog( "file_size: $g_size", 0 );
}
else {
print TMP "file_size: $g_size\n";
close TMP;
}
$/ = "\n";
close FILE;
}
输入文件格式:
>one
AAAAA
>two
BBB
>three
C
我有几个具有该格式的输入文件。以“&gt;”开头的行是相同的,但其他线可以是不同的长度。只有一个文件的函数输出是:
one 5
two 3
three 1
我想在每个文件的循环中执行该函数:
foreach my $file ( @refs ) {
fileSize( $file, 1 );
}
运行下一次迭代时,假设使用此文件:
>one
AAAAABB
>two
BBBVFVF
>three
CS
我想获得这个输出:
one 5 7
two 3 7
three 1 2
如何修改功能或修改脚本才能获得此功能?可以看出,我的函数将文本附加到文件
谢谢!
答案 0 :(得分:1)
您需要打开输出文件本身。首先处于读取模式,然后处于写入模式
我写了一个脚本来做你要求的。真正重要的是将新数据附加到旧数据的部分。将其改编为fileSize
函数。
所以你有输出文件output.txt
表格中,
one 5
two 3
three 1
一系列输入文件input1.txt
,input2.txt
等保存在@inputfiles
变量中。
表格中,
>one
AAAAA
>two
BBB
>three
C
>four
DAS
和
>one
AAAAABB
>two
BBBVFVF
>three
CS
分别
运行以下perl脚本后,
# First read previous output file.
open OUT, '<', "output.txt" or die $!;
my @outlines;
while (my $line = <OUT> ) {
chomp $line;
push @outlines, $line;
}
close OUT;
my $outsize = scalar @outlines;
# Suppose you have your array of input file names already prepared
my @inputfiles = ("input1.txt", "input2.txt");
foreach my $file (@inputfiles) {
open IN, '<', $file or die $!;
my $counter = 1; # Used to compare against output size
while (my $line = <IN>) {
chomp $line;
$line =~ m/^>(.*)$/;
my $name = $1;
my $sequence = <IN>;
chomp $sequence;
my $seqsize = length($sequence);
# Here is where I append a column to output data.
if($counter <= $outsize) {
$outlines[$counter - 1] .= " $seqsize";
} else {
$outlines[$counter - 1] = "$name $seqsize";
}
$counter++;
}
close IN;
}
# Now rewrite the results to output.txt
open OUT, '>', "output.txt" or die $!;
foreach (@outlines) {
print OUT "$_\n";
}
close OUT;
您生成输出
one 5 5 7
two 3 3 7
three 1 1 2
four 3
答案 1 :(得分:1)
我遗漏了你的选项和文件IO操作,并专注于通过命令行显示一个使用数组数组的方法。我希望它有所帮助。我将把它连接到你自己的脚本和子程序,主要取决于你:-)
针对您的第一个数据文件运行此一个衬垫:
perl -lne ' $name = s/>//r if /^>/ ;
push @strings , [$name, length $_] if !/^>/ ;
END { print "@{$_ } " for @strings }' datafile1.txt
给出了这个输出:
one 5
two 3
three 1
替换数据文件的第二个版本或实例(即,其中记录one
包含AAAAABB
)也会给出预期结果。
one 7
two 7
three 2
在上面的脚本中,您将以此格式保存到输出文件。因此,要将列附加到输出文件中的每一行,我们可以以相同的方式处理每个数据文件(幸运的是,这可能意味着可以将事物转换为可在foreach
中运行的函数环)。如果我们将转换后的数据保存为array of arrays(AoA),那么我们只需将push
我们为每个数据文件字符串获取的length
值放到相应的匿名数组元素上,然后打印出阵列。瞧!现在让我们希望它有效; - )
您可能希望安装Data::Printer
,可以在命令行中使用-MDDP
作为> /tmp/output.txt
来可视化数据结构。
DDP
接下来 - 试试这个使用p
和perl -MDDP -lne 'BEGIN{ local @ARGV=shift;
@tmp = map { [split] } <>; p @tmp }
$name = s/>//r if /^>/ ;
push @out , [ $name, length $_ ] if !/^>/ ;
END{ p @out ; }' /tmp/output.txt datafile2.txt `
的长单行显示我们创建的数组的结构:
BEGIN
在local
区块中,我们@ARGV
- ize shift
; TMP
关闭第一个文件(我们的{local @ARGV=shift}
文件版本) - split
几乎是用于处理多个输入文件的perl习惯用法;然后我们[]
在匿名数组构造函数(map { }
)和@tmp
内进入DDP
数组,我们用p()
的{{1}}显示功能。一旦我们离开BEGIN
块,我们用perl的while (<>){ ... }
命令行开关得到的隐式-n
接管并从@ARGV
读入剩余的文件;我们处理以>
开头的行 - 剥离前导字符并将后面的字符串分配给$name
变量; while
继续,我们push
$name
以及不以length
(>
)开头的任何行的if !/^>/
包含为匿名数组[]
进入@out
数组,我们也会在p()
块中显示END{}
块,因此不会在隐式while()
内打印环)。唷!
查看结果为gist @Github的AoA。
END{...}
块中更改一些内容(向for
周围添加嵌套push
循环)并把它们放在一起产生我们想要的输出。这一个班轮:
perl -MDDP -lne 'BEGIN{ local @ARGV=shift; @tmp = map {[split]} <>; }
$name = s/>//r if /^>/ ; push @out, [ $name, length $_ ] if !/^>/ ;
END{ foreach $row (0..$#tmp) { push $tmp[$row] , $out[$row][-1]} ;
print "@$_" for @tmp }' output.txt datafile2.txt
产生
one 5 7
two 3 7
three 1 2
我们必须将其转换为脚本: - )
该脚本由三个相当冗长的子程序组成,这些子程序读取日志文件;解析数据文件;合并它们。我们按顺序运行它们。第一个检查是否存在现有日志并创建一个,然后执行exit
以跳过任何进一步的解析/合并步骤。
您应该能够将它们包装在某种循环中,这种循环将文件从数组提供给子例程,而不是从STDIN
获取它们。一个警告 - 我正在使用IO::All
因为它很有趣而且很容易!
use 5.14.0 ;
use IO::All;
my @file = io(shift)->slurp ;
my $log = "output.txt" ;
&readlog;
&parsedatafile;
&mergetolog;
####### subs #######
sub readlog {
if (! -R $log) {
print "creating first log entry\n";
my @newlog = &parsedatafile ;
open(my $fh, '>', $log) or die "I CAN HAZ WHA????" ;
print $fh "@$_ \n" for @newlog ;
exit;
}
else {
map { [split] } io($log)->slurp ;
}
}
sub parsedatafile {
my (@out, $name) ;
while (<@file>) {
chomp ;
$name = s/>//r if /^>/;
push @out, [$name, length $_] if !/^>/ ;
}
@out;
}
sub mergetolog {
my @tmp = readlog ;
my @data = parsedatafile ;
foreach my $row (0 .. $#tmp) {
push $tmp[$row], $data[$row][-1]
}
open(my $fh, '>', $log) or die "Foobar!!!" ;
print $fh "@$_ \n" for @tmp ;
}
子程序在这里完成所有工作 - 你可能会找到缩短的方法;结合;改善它们。这对你来说是一个有用的方法吗?
我希望这个解释对某人来说是明确和有用的 - 欢迎更正和评论。可能同样的事情可以通过地点编辑(即与perl -pie '...'
)完成,这可以作为练习留给后面的人......