根据网易云课程整理,禁转
子程序sub编写
- 子程序声明sub
- 子程序可以传入数组/哈希
- 默认变量@_ 用于传递参数
- 子程序调用&
- 变量的作用域:子程序中定义的变量作用域只能在子程序中调用,子程序可以调用全局变量
- 返回值return
#子程序示例
sub hello{
my($name) = @_;
#传入的是一个数组 @_,列表上下文将数组第一个元素赋值给$name
print "Hello $name !\n";
}
&hello("Tom","Lucy");
sub hello1{
print "Hello $_[0] !\n";
#从数组@_中获取第一个元素,效果同上(不是$_老地方)
}
&hello1("Tom","Lucy");
#数组求和
sub sumNum{
my@num=@_;
my $sum = 0;
for my$n(@num){
$sum=$sum+$n;
}
return $sum;
}
my $all = &sumNum(1..5);
print "$all\n";
#哈希打印
sub show_hash{
my %hash = @_;
for my $k(keys %hash){
print"$k: $hash{$k}\n";
}
}
&show_hash({"name"=>"a", "number"="b"});
命令行参数传递
内置变量@ARGV
使用@ARGV传递参数可以使脚本更通用
数组:用于存储命令行里的字符串
open(IN, "$ARGV[0]") or die"$!";
open(OUT, "$ARGV[1]") or die "$!";
命令行:perl my_script.pl ./test.txt ./out.txt
注意:文件传入顺序必须对应
打印使用帮助
示例
die "perl $0 <in> <out>" unless(@ARGV == 2);
$0 特殊标量,脚本名
只有当传入参数为2个时,命令运行,否则die,并打印die后的字符串
perl调用系统命令
- system 可以批量调用系统命令
也可以调用perl程序system("perl my_perl.pl");
可以用``代替,如:`perl my_perl.pl`; 效果同上
如果system里的命令正常退出,返回0;非正常退出返回错误信息 - glob 可以批量抓取一个目录中的文件,返回一个数组
可以指定前缀glob(D:/1*)D盘下开头为1的文件
可以指定后缀glob(D:/*fasta)D盘下结尾为fasta的文件 - 注意:最好写文件的绝对路径
数据:
在/home/perl_test/fasta_files/文件夹下有n个fasta文件,文件名为 编号.fasta
用于比对的参考序列 ref.fa
要求:
写一个perl脚本my_perl.pl,用blastall对n个fasta文件进行批量比对
my $dir = "/home/perl_test/";
my @files = glob("$dir/fasta_files/*fasta");
for my $i (@files){
print "$i\n"; #检查输入文件路径
print "blastall -i $i -d $dir/blastdb/ref.fa -e 1e-10 -p blastp -m 8 -o $i.out\n"; #检查命令行
my $err = system("blastall -i $i -d $dir/blastdb/ref.fa -e 1e-10 -p blastp -m 8 -o $i.out"); #调用系统命令
if($err){
print "$err\n";
} #如果有错误打印错误信息
}
命令行输入:perl my_perl.pl
perl中使用第三方包
在脚本开头调用包:use 包名 qw(变量名/方法名);
命令行安装示例:cpan Data::Dumper
use strict;
# 创建变量时必须用my进行声明
use Data::Dumper;
# 打印变量,比如哈希
print Dumper (\%hash);
use List::Util qw(sum max min);
#求数组和,最大值,最小值
my @num = (1..5);
my $sum_num = sum(@num);
print "$sum_num\n";
路径处理包
use FindBin qw($BIn $Script);
# $BIn,$Script为包中自带变量
# $Bin 存储脚本所在根目录
# $Script 存储脚本文件名
# 方便用于流程编写时调用同级目录中的脚本
print "\$Bin: $Bin\n";
use File::Basename qw(basename dirname);
# 处理环境路径
if (@ARGV>0){
print "\$ARGV[0]: $ARGV[0]\n";
my $bname = basename($ARGV[0]); #路径最后一个文件名/文件夹名
print "basename: $bname\n";
my $dname = dirname($ARGV[0]);
print "dirname: $dname\n";
}
use Cwd qw(abs_path getcwd);
# getcwd 返回使用者使用的当前路径
my $present_work_dir = getcwd();
print "\$present_work_dir: $present_work_dir\n";
# abs_path 返回文件的绝对路径
my $absP = abs_path($ARGV[0]);
print "\$absP: $absP\n";
Getopt::Long传递参数
use strict;
use Geropt::Long;
use Data::Dumper;
my @libs = ();
my %flags = ();
my ($verbose, $all, $help, $test, $step, $type) = ();
GetOptions(
'help!' => \$help,
'step:i' => \$step,
'type=s' => \$type,
'lib=s' => \@libs,
'flag=s' => \%flags,
'test|t:s' => \$test,
'all|everything|universe:s' => \$all,
);
# 'help!' 接有!的选项不接受变量( -help 直接使用)
只要命令行中出现了这个参数,就会默认是1,用来设置打开/关掉一个功能
# : 和 = 都可以接受字符串(s)、整数(i)、浮点(f)等类型的变量
# 'step:i' 接有:的选项可以接受缺省,0或者空字符串(比如-step 那么$step的值为0)
# 'type=s' 接有=的选项不接受缺省(比如-type 相当于没设置)
# 'lib=s' 如果相关联的变量是个数组,比如此处的@libs,那么选项可以多次出现,所有值将被追加进数组(-lib /test.txt -lib /test1.txt)
# 'flag=s' 如果相关量的变量是个哈希,那么选项接收一个键值对,并保存进哈希(-flag aa=1 -flag bb=1)
# 'test|t:s' 接有| 的选项表示可以将-test简写为-t
# 'all|everything|universe:s' 表示all everything universe都指向$all
#备注:GetOptions可以自动简化命令,所有选项可以被简写为唯一的最短字符串,如果首字母相同会加上第二字母来区分,效果跟写全相同(比如-help在命令行中可以写成-h)
#在匹配参数名的时候,GetOptions在缺省设置下会忽略大小写
sub USAGE{
my $usage = <<"USAGE"; #注意<<,将下面的内容原样存在$usage中
Usage:
Options:
-verbose whether do somthing
-help note
-step note
-type note
-lib test \@ #因为是字符串,所以@需要转义
-flag test \%
...
USAGE #到这里结束存储,注意USAGE顶格
print $usage;
exist;
}
&USAGE unless (!$help);
#unless如果判断语句为false,执行(即:如果输入-help将打印帮助)
&USAGE unless (!$help and $type);
#意思是$type里必须有值,如果没有输入值,也会打印帮助
$step||=1;
#||意思是如果前面的部分为false,那么变量赋值为1(即:如果$step没有输入值,那么默认赋值为1)注意一个bug:如果$step 0那么也会自动赋值为1
#测试代码
print "\$verbose :$verbose\n";
print "\$help:$help\n";
print "\$step:$step\n";
print "\@libs:@libs\n";
print "\%flags: ".Dumper(\%flags)."\n";
print "\$test:$test\n";
print "\$all:$all\n";
85



被折叠的 条评论
为什么被折叠?



