Perl进阶笔记(仅此一篇,持续更新)

目录

    1. pod文档
    1. Getopt::Long
    1. perl单行
    1. 使用Hash遇到的坑
    1. Hash中的排序操作
    1. 安装Perl模块
    • 6.1. 使用CPAN模块自动安装
    • 6.2. 手工安装
    • 6.3. 非root用户的另一个解决方案
    1. 循环匹配
    1. chomp带来空行匹配的失败
    1. perl中的grep函数

1. pod文档

使用pod文档可以实现程序usage说明

=head1 part1

    doc in part1

=head2 part2

    doc in part2

.
.
.

=cut    # pod文档结束的标志

注意:每个=标签上下必须隔一行,否则就会错误解析。

pod2doc $0可以将程序中的文档打印出来,不过一般用在程序内部,当程序参数设定错误时打印pod文档:

die `pod2doc $0` if (...);

2. Getopt::Long

首先需要在脚本开头加上对该模块的引用

use Getopt::Long;

使用GetOptions函数承接传递的参数:

my ($var1,$var2,$var3,$var4); # 若使用"use strict"模式,则需要提前定义变量
GetOptions(
    "i:s"=>\$var1,
    "o:s"=>\$var2,
    "n:i"=>\$var3,
    "m:i"=>\$var4
    );

3. perl单行

执行perl -h可以查看perl的所有参数使用说明,使用perl单行需要使用到-e参数

$ perl -e 'print "hello world!\n"'

perl单行常用的场景为进行文本的逐行读取并操作,即隐式地开启while(<>),需要使用-n参数

perl -ne
    'BEGIN{}
    ...
    END{}'
filename

BEGIN 和 END 区块根据需要进行添加

若需要在逐行读取的同时,自动将行中的元素打散 (split),默认以\s(空字符,即空格或制表符)作为分割符,则需要使用-a参数,相当于在执行了@F = split $_,打散后的元素会保存在@F

4. 使用Hash遇到的坑

在编写perl脚本的过程中,我们常常会将读入文件一行中的某两项(一行可能有多列,列与列之间用制表符\t隔开)作为相对应的两项,分别作为Hash的键(key)和值(value),由于Hash这种数据结构要求key是唯一,而value可以重复,因此一般将唯一的那一项作为key,另一项作为value

但是,由于字符串首末端空字符的存在会导致一个意想不到的情况:

创建了两个Hash,让它们的key是一一对应的,而各自存储的value不同,当时在某些key字符串首末端混入了空字符,例如Hash1有一个key为"KEY",Hash2有一个key为"KEY ",它们本来应该是一样的,但是由于空字符的存在,它们现在不一样了

这时候的解决方法是在构建Hash之前,不论实际的字符串的首末端有没有空字符串,都尝试将这些空字符串去掉:

# 假设读入的文件只有用制表符隔开的两列
while(<IN>){
    chomp;
    @recorder = split /\t/;
    $recorder[0] =~ s/(^\s+)|(\s+$)//g; # 去除开头和末尾的空字符串
    $recorder[1] =~ s/(^\s+)|(\s+$)//g; # 去除开头和末尾的空字符串
    $hash{$recorder[0]} = $recorder[1];
}

5. Hash中的排序操作

对key进行排序

其基本的语法结构为:

sort <排序规则> <排序对象>

若要对keys进行排序则排序对象就是keys,所以最后一项要写成keys %hash

# 按value排序
## 对hash的keys按hash value排序(按ASCII码排序)
sort { $hash{$a} cmp $hash{$b} } keys %hash
## 对hash的keys按hash value排序(按数字大小排序)
sort { $hash{$a} <=> $hash{$b} } keys %hash

# 按key排序
# 对hash的keys按hash key排序
sort {$a<=>$b} keys %hash

6. 安装Perl模块

查看perl模块的安装目录,主要就是@INC这个默认变量

perl -e '{print "$_\n" foreach @INC}'

若要临时添加perl模块的安装目录,则在perl脚本中shebang(#!/usr/bin/perl)后紧接着添加push(@INC,"...");命令,若是在perl单行中,则写成BEGIN{push(@INC,"...");}

若是要永久添加perl模块的安装目录,则修改PERL5LIB环境变量即可:

export PERL5LIB=/PATH/TO/LIB

查看已安装的Perl模块:

# 查看系统中安装的Perl模块
find  `perl -e 'print "@INC"'` -name '*.pm'
# 查看当前环境下所有的模块(一般为用户自己安装的)
instmodsh

查询单个perl模块的安装路径:

perldoc -l Getopt::Long

查看安装的perl模块的版本号

perl -MGetopt::Long -e 'print Getopt::Long->VERSION. "\n"'

装Perl模块有两种方法

  • 自动安装 (使用CPAN模块自动完成下载、编译、安装的全过程)
  • 手工安装 (去CPAN网站下载所需要的模块,手工编译、安装)

6.1. 使用CPAN模块自动安装

首先你得已经安装了CPAN,若没有执行以下命令:

# yum install perl-CPAN

安装前需要先联上网,有无root权限均可

$ perl -MCPAN -e shell
cpan>help
cpan>m
cpan>install Net::Server
cpan>quit
  • 查询:cpan[1]> d /模块名字或者部分名字/

查询结果中会给出所有含有模块名字或者部分名字的模块,选择您所需要的模块进行下载

  • 下载安装:cpan[1]> install 模块名字

同时会自动安装很多依赖的模块,非常方便。

6.2. 手工安装

一般情况下不推荐这种安装方式,但是总是会有迫不得已的时候,而且尝试这种方式,能加深对perl模块的理解。

比如从 CPAN下载了Net-Server模块0.97版的压缩文件Net-Server-0.97.tar.gz,假设放在/usr/local/src/下。

cd /usr/local/src
tar xvzf Net-Server-0.97.tar.gz
cd Net-Server-0.97
perl Makefile.PL
make test

如果测试结果报告all test ok,你就可以放心地安装编译好的模块了。

6.3. 非root用户的另一个解决方案

手动下载local::lib, 这个perl模块,然后自己安装在指定目录,也是能解决模块的问题!

下载之后解压,进入:

perl Makefile.PL --bootstrap=~/.perl ##这里设置你想把模块放置的目录
make test && make install
echo 'eval $(perl -I$HOME/.perl/lib/perl5 -Mlocal::lib=$HOME/.perl)' >> ~/.bashrc ##目录与前面要一致

等待几个小时即可!!!

添加好环境变量之后,就可以用

perl -MCPAN -Mlocal::lib -e 'CPAN::install(LWP)'

或有更简单的写法:

cpanm --local-lib=~/perl5 local::lib && eval $(perl -I ~/perl5/lib/perl5/ -Mlocal::lib)

7. 循环匹配

在李恒的github博客 On the definition of sequence identity 当中看到这样一个Perl单行代码:

$ perl -ane 'if(/NM:i:(\d+)/){$n=$1;$l=0;$l+=$1 while/(\d+)[MID]/g;print(($l-$n)/$l,"\n")}'

这行代码的目的是为了计算SAM文件中每条记录BLAST identity

BLAST identity是根据你比对到的碱基除去比对所涉及到的columns数目,换句话来说就是比对涉及到所有的碱基数目

例如这样的双序列比对:

Ref+:  1 CCAGTGTGGCCGATaCCCcagGTtgGC-ACGCATCGTTGCCTTGGTAAGC 49
         |||||||||||||| |||   ||  || ||||||||||||||||||||||
Qry+:  1 CCAGTGTGGCCGATgCCC---GT--GCtACGCATCGTTGCCTTGGTAAGC 45

它们的BLAST identity就是43/50=86%

那么要计算SAM文件中每条reads的BLAST identity,总长可以通过叠加CIGAR中对应的M/I/D的数目得到,比对到的碱基数目等于总长减去NMtag(比对不上的碱基位置的标记)

李恒的这行代码中有一部分一开始没有读懂,就是下图红框中的那部分:

其实这是一种简写方式,正规完整且更容易读懂的形式可以写成下面这样:

# 这里为了更好看,添加了适当的换行和缩进

$ perl -ane \
'if(/NM:i:(\d+)/){
    $n=$1;
    $l=0;
    while(/(\d+)[MID]/g){
        $l+=$1;
    }
    print(($l-$n)/$l,"\n");
}
'

while(/(\d+)[MID]/g)中的正则表达式/(\d+)[MID]/g,引起了我极大的好奇:它是在正则表达式后面添加了一个g字符,即开启了全局匹配,又由于是在while( )中进行的正则匹配,等于是开启了循环匹配,即对于CIGAR字符串18M3D22M,正则表达式/(\d+)[MID]/g,先会匹配上18M,然后会匹配上3D,最后匹配上22M

很有意思的用法

8. chomp带来空行匹配的失败

我常用正则表达式/^\s+$/来进行文件中空行的匹配

在用perl单行进行文本处理,我喜欢用一个固定的格式:

$ perl -ne 'chomp;...' <input>

chomp在这里的作用是在每读入一行后,去除末尾的换行符

此时如果你要匹配的空行是/^\n/形式的,即这行只有一个换行符,被chomp处理过之后这一行就变成了/^$/形式的空字符的行,此时如果再用正则表达式/^\s+$/进行匹配,就会匹配失败

那么遇到这种情况应该怎么匹配呢?

使用/^\s?$/即可,元字符?的作用是匹配前面的字符0到多次

9. perl中的grep函数

grep有2种表达方式:

grep BLOCK LIST
grep EXPR, LIST

BLOCK表示一个code块,通常用{ }表示;

EXPR表示一个表达式,通常是正则表达式。原文说EXPR可是任何东西,包括一个或多个变量,操作符,文字,函数,或子函数调用;

LIST是要匹配的列表

grep的工作原理:

grep对列表里的每个元素进行BLOCK或EXPR匹配,它遍历列表,并临时设置元素为$_

在列表上下文里,grep返回匹配命中的所有元素,结果也是个列表。在标量上下文里,grep返回匹配命中的元素个数。

实例一:

open FILE "<myfile" or die "Can't open myfile: $!";
print grep /terrorism|nuclear/i <FILE>;

打开一个文件myfile,然后查找包含terrorism或nuclear的行。<FILE>返回一个列表,它包含了文件的完整内容。可能你已发现,如果文件很大的话,这种方式很耗费内存,因为文件的所有内容都拷贝到内存里了

实例二:

foreach my $infile (grep { !/^\./ && -f "$indir/$_" } readdir(DIR)){
    ...
}

readdir(DIR)读入指点文件夹句柄DIR下的所有文件(包括以.开头的隐藏文件)的文件名,构成一个文件名列表 (list),然后每一次读入一个文件名保存到临时变量$_中,传递给grep处理,先用!/^\./判断文件名是否以.开头,保证该文件不是隐藏文件,接着,通过-f "$indir/$_"判断该文件是否存在


参考资料:

(1) 生信菜鸟团:perl模块安装大全

(2) Heng Li's blog: On the definition of sequence identity

(3) 【简书】生信杂谈:怎样定义sequences比对的相似度?

(4) perl中grep的详细用法

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容

  • 2009 有用的和有意思的循环 让我们来看一个基本的例子. 这是一个最简单清晰的语法的例子.在这并没有使用括号来包...
    焉知非鱼阅读 484评论 0 0
  • ############原文粘贴#################### 用 Perl 实现的有用的单行程序 ...
    sunslj阅读 1,106评论 0 4
  • 城市的夜晚总是那么亮堂,夜再没有了那般漆黑,薄薄地像一层深蓝色的纱般笼罩着大地。晚上,看着四处照明的路灯,看到对面...
    胖绒球阅读 506评论 2 6
  • 夏天来了,龙虾散落在大中国的各个角落,其实我不太爱这玩意,为啥?自从去年搬家之后,连续吃了两个月的小龙虾,已经让我...
    拯救地球者阅读 320评论 0 1
  • 到2017年底了,最怕有人问起:你2016年的年初计划完成了吗?不对!你2015年的计划完成了吗? 答案肯定是没完...
    伸个小懒腰阅读 383评论 0 1