1、for/while/if
- 后两者在前面的例子中均有说明,不再赘述了
- for与foreach是等价的,即可以互换
见一个简单例子
#!/usr/bin/perl -w
use strict;
for (my $i=1;$i<=10;$i++) {
# 分别为起始值、判定条件、变化规则
print "$i\n"
}
or
#!/usr/bin/perl -w
use strict;
for (1..10){
print "$_\n"
}
懒惰即美德,所以有时越简单越好,比如--
print "$n is a negative number\n" if ($n<0);
print "$_\n" for (1..10);
print "$_\n" while (<IN>);
2、循环控制
主要有两个--
- next 表跳过,执行下一循环;
- last 表在特定条件下终止循环;
#!/usr/bin/perl -w
use strict;
for (1..10) {
if ($_==5) {
next; #1234678910
#last; #1234
} else {
print "$_\n";
}
}
例如在一个含有几万条序列的基因集中寻找某一特定基因,找到后即可终止,没有必要再执行。这一过程很好地结合了
last
与next
的使用。
while (<IN>) {
chomp;
if (exists $hash{$_}) {
print "$_\n";
last; #找到后直接终止
} else {
next; #跳过,执行下一循环
}
}
3、elsif语句
- 适用于分级别,等级,年龄段等可以是多种选择、归类的情况。
下面一个例子是根据成绩分等级的经典例子
#!/usr/bin/perl -w
use strict;
print "Enter your score:";
chomp (my $score=<STDIN>);
#实现交互式输入
if ($score==100) {
print "Excellent\n";
} elsif ($score >=90 && $score <100 ) {
print "Very Good\n";
} elsif ($score >=80 && $score <90) {
print "Good\n";
} elsif ($score >=70 && $score <80) {
print "OK\n";
} elsif ($score >=60 && $score <70) {
print "Pass\n";
} else {
print "You need to work hard\n";
}
注意elsif的书写,不要写成elseif了。
补充1:if另一种写法
(<1>) ? <2> : <3> ;
若<1>为真就执行<2>,否则执行<3>
#!/usr/bin/perl -w
use strict;
print "Enter your score:";
chomp (my $score=<STDIN>);
my $result=
($score==100) ? "Excellent" :
($score >=90 && $score <100 ) ? "Very Good" :
($score >=80 && $score <90 ) ? "Good" :
($score >=70 && $score <80 ) ? "OK" :
($score >=60 && $score <70 ) ? "Pass" :
"You need to work hard";
print "$result\n";
补充2:逻辑与或
&&
:两真才真(见上例)
( ) && ( );
表示若左为真,就执行右||
:一真则真
( ) || ( );
表示若左真,则不执行右;相反则执行右。
$ARGV[1] || =20;
表示第二个参数不输入就默认为20,否则就按输入参数计算。
4、循环批量生成生信脚本例子
- 目的:blast序列比对找同源序列,但是当序列文件过大相当耗时。可以将大文件拆分成多份小文件,进行多线程blast,可以大幅提高效率。最后将结果合并即可。
grep ">" gene.ffn | wc
先了解gene中含有多少条序列,大概要分成多少份。
#!/usr/bin/perl -w
use strict;
my @seq=(); #定义空数组,存储序列
my $part||=50; #设置默认分成50份
chomp (my $num=`grep ">" $ARGV[0] |wc -l`); # -l 选项
my $i=1;
my $j=int ($num/$part); #向下取整,求每份中包含的序列数
my $outdir="split"; #为小份序列文件创建存储文件夹
`mkdir $outdir`;
#语法见下补充
open IN,"$ARGV[0]"; #打开序列文件
$/=">";<IN>;
#此循环去除ID开头大括号,并将序列内的换行符删去,并最终将所有序列储存到一个数组中。
while (<IN>) {
chomp;
next if (/^>/);
my ($id,$seq)=(split /\n/,$_,2)[0,1];
$seq=~ s/\n//g;
my $out="$id\n"."$seq"; #除了没有大于号,且序列无换行符,其余格式与fasta相同
push @seq,$out; #push 添加
}
close IN;
$/="\n"; #更改分隔符
open SH,">blast.sh"; #批量脚本文件
# 循环思路例如4000条序列分成50份,每份近80条。
# 外循环为份数 50次
# 内循环为每份序列数 80次
for (my $i=1;$i<=$part;$i++) {
open OU,">$outdir/split_$i.fa";
foreach (0..$j-1) {
my $out=shift @seq; #每次在开头取一条序列
print OU ">$out\n"; #按标准fasta格式写入到 $outdir/split_$i.fa
}
print SH "blastall -i $outdir/split_$i.fa -d $ARGV[0] -o $outdir/split_$i.blast -m 8 -e 1e-5 -p blastn -a 2 -F F;\n";
#每一次大循环即编写一个blast脚本
}
perl 1.pl gene.ffn
补充:`mkdir $outdir`; 是perl脚本中使用了Linux命令;使用方法就是在perl
脚本中,给Linux命令两边加上反引号 ` (Esc下面那个键)即可。例如
- 创建目录
#!/usr/bin/perl -w
use strict;
chomp (my $pwd=`pwd`); #注意有换行符,需要去掉
`mkdir $pwd/test`;
- 记录脚本运行时间
#!/usr/bin/perl -w
use strict;
#记录脚本执行时间
my $start=`data +%Y-%m-%d-%R`;
#置于脚本开头
my $end=`data +%Y-%m-%d-%R`;
#置于脚本结尾