Perl One-Liners | Perl命令行学习5 $/和$\变量

Perl 特殊变量$/$\

上集回顾

上次我们看了一下-M-I这两个搭档
这次我们来看看这两个特殊的”变量“$/$\,不是参数。

解释

$/ : 输入记录分隔符
$\ : 输出记录分隔符

说实话,这两个符号的确是有些诡异!可以这么来记,“太阳出来我爬山坡,爬上山坡我好唱歌”,爬坡的是/(入),下坡的是\(出)。

这两个变量是特殊变量,什么意思呢?就是它们是从娘胎里来的,本来就有,不需要你去声明,它们就在那里。

为什么要说这两个变量呢?这两个变量是什么意思呢?下面先说明一下这两个奇特的怪物究竟是个什么玩意。

比如在工厂车间的流水线,生产罐头的那种。

   [] [] [] [] [] [] [] [] [] [] [] []
->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->
| O  O  O  O  O  O  O  O  O  O  O  O  O  O  O  O |
<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<-
当得到成品罐头之后,需要装箱了,可是多少个装一箱呢。
这个时候就有机器负责控制履带移动的长度来控制几个罐头为一组进行装箱(罐头之间间距相等)。
比如4个罐头装一箱,那好,当过了一定长度之后传送带停下来,机械臂将4个罐头装箱,OK
                          |===================
                          -
                         | |
                          |
   [] [] [] [] [] [] [] [] [] [] [] []
->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->
| O  O  O  O  O  O  O  O  O  O  O  O  O  O  O  O |
<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<-

下一批
                          |===================
                          -                         ---------
                         | |                        | [] [] |
                          |                         | [] [] |
               [] [] [] [] [] [] [] []              --------- 
->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->  ####################
| O  O  O  O  O  O  O  O  O  O  O  O  O  O  O  O |  ####################
<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<-  ####################

再下一批
                          |===================
                          -                         --------- ---------
                         | |                        | [] [] | | [] [] |
                          |                         | [] [] | | [] [] |
                           [] [] [] []              --------- --------- 
->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->  #################### 
| O  O  O  O  O  O  O  O  O  O  O  O  O  O  O  O |  ####################
<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<-  ####################
假如我的包装箱变大了,这次要装6个,怎么搞,好办,设置一下传送带每次传送的长度就OK可
                          |===================      ---------
                          -                         | [] [] |
                         | |                        | [] [] |
                          |                         | [] [] |
                           [] [] [] [] [] []        ---------
->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->  #################### 
| O  O  O  O  O  O  O  O  O  O  O  O  O  O  O  O |  #################### 
<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<-  #################### 
有的时候厂家搞活动,在箱子里面除了有罐头,还有小礼品哟。

---------
| [] [] |--|            +++
| [] [] |  |            +++ 小礼品,比如杯子,哈哈
| [] [] | +++
--------- +++

^^^^^^^^^^
||||||||||
上面是一个装罐头的箱子,外面用绳子系了个礼物在外面,我怕我灵魂画手的功力太深,你们认不出来~~

这里不妨把perl的文本处理流程当作是工厂中的流水线,每次读取一“行”,来处理。

  • $/就是说在什么地方将文本分隔开来作为一组”罐头“,类似于控制传送带移动的长度。
  • $\就是当我想打印文本的时候后面带的小尾巴是什么,就像是上面的小礼品一样。

现实世界与机器世界

《Perl One-Liners | Perl命令行学习5 $/和$\变量》 现实世界.JPG

《Perl One-Liners | Perl命令行学习5 $/和$\变量》 机器世界.JPG

平常我们读书,从左到右转头就是一行。但是在机器世界,究竟什么是“行”,其实计算机的存储是连续的,并不是说想现实世界那样还转行之类的。那么究竟是如何区分行与行呢?
比如有一段序列

ATGCGTAGCTA
TAGCTAGCTTG
AA

其实真实的是这样的

ATGCGTAGCTA\nTAGCTAGCTTG\nAA

当然了,更加还原是以1和0表示,这里为了方便叙述。也就是说在这三“行”序列之间是用一个\n连起来的,并不是像现实世界转头之类的。机器为了区分,每次读到\n,就知道了到了一“行”了。
上面两张图说明了现实的书本纸和机器世界的区别LF就是指\n。这个就是为了告诉机器要“换行了”。那么这里Perl不仅可以要机器在\n的地方换行,也可以自己设置如果碰到什么字符那就换行,比如!~@等等。

我之前有一个同学在处理文本的时候没有将末尾的那个不可见的换行符去除,导致正则表达式无法匹配,也就无法得到正确结果,但是他换成从命令行输出那一行信息却可以匹配(从命令行读取的不包含换行符)。一直纠结,后来我给他说了,他一直不相信,知道后来事实证明他没搞清楚这个换行符。

额,可能被我搞的糊涂了,来看看例子就明白啦!

用法

$/ = "\n";
$\ = "\n";

这两个就是变量,也就是说可以直接对他们赋值

实例

  • 示例1
# 这次不用-a与-F参数来处理
echo "12-34-56,45-23-67,678-56-12" | perl -n -e '
    BEGIN{
        # 在读取数据之前就设置好输入记录分隔符
        # 设置 , 作为“一行”的结尾的标志
        $/ = ",";
    }
    # 在将读取的每一“行”的一系列用 - 连起来的数值进行分隔
    my @list = split /-/,$_;
    # 对每组数值求和
    my $total = 0;  # 初始化变量
    for my $num (@list){
        $total += $num;
    }
    print "$total\n";
'

# 输出
102
135
746

这里来解释一下

        |        |
        v        v
12-34-56,45-23-67,678-56-12

箭头所指的就是每次读取的”一行“的停止位置,平常我们一般都是认为换行符才是一行的末尾,但是这里$/大哥说了,机器人的世界中的天上天下的——换行,都归我管 。也就是说这里它重新定义了行的概念,就是说,按照,来作为标志。比如

机器读
12-34-56,
这是”一行“
再读
45-23-67,
这是”一行“
在读
678-56-12
这是”一行“

这里的“行”是指机器读的行

来点实际的东西

  • 示例2

假如有一个文件123.txt,内容为

>atp1
AGTCAGCTGACTCGATCTACGTCTAGCGACGT
GATACGTACGTACGGTACTCGTAGCTACCGTA
TAGTAGC
>cox
ATGCGTAGCTATCGTAGCTAGCTCGATCGTCA
AGTAGCTCAGG
>nad1
ATGCTAGCTGACTTGACTGCATACGATGCTAG
GTAGTCATGCTAGCTAGC

其实在平常我们碰到很多fasta文件,它的序列是按照80个碱基为一行就进行了换行了,所以我们后续处理有些麻烦。比如我们想要得到名为atp1的序列,那么就是当我判断了到了atp1之后,接下来就是序列,可是只打印出>atp1下面的一行却不是它的完整序列,还需要继续打印,直到碰到>cox,这样其实某种程度上来说就有点不太方便。

怎么做呢?你根据今天说的内容应该想出来怎么办了吧!

# 使用 > 作为输入分隔符
# 代码如下
cat 123.txt | perl -n -e '
    BEGIN{
        $/ = ">";
    }
    # 由于是以 > 作为分隔符,那么尾巴处就可能有>符号(除了最后一行可能没有其他都有)
    $_ =~ s/>$//;
    
    # 正则表达式中\s*\r*使因为不只知道在atp1后面是否有空格和回车符,所以加上
    if($_ =~ m/^atp1\s*\r*\n/){
        # 1. 也可以在这里除去里面的换行符
        # print (substr($_,length($&)) =~ s/\r*\n//gr);
        # 2. 也可以不去除
        print ( substr($_,length($&) );
    }
'

# 输出为
AGTCAGCTGACTCGATCTACGTCTAGCGACGT
GATACGTACGTACGGTACTCGTAGCTACCGTA
TAGTAGC

这里我把分隔出来的每一批字符写一下

  1. 第一批
>
  1. 第二批
atp1
AGTCAGCTGACTCGATCTACGTCTAGCGACGT
GATACGTACGTACGGTACTCGTAGCTACCGTA
TAGTAGC
>
  1. 第三批
cox
ATGCGTAGCTATCGTAGCTAGCTCGATCGTCA
AGTAGCTCAGG
>
  1. 第四批
nad1
ATGCTAGCTGACTTGACTGCATACGATGCTAG
GTAGTCATGCTAGCTAGC

注意:由于这里我们对机器世界的行进行了重新定义,在这每一“行”中就可能存在多个\n,而“行”的结尾就变成了>

$\

这个参数就是说当输出的时候,在输出的内容后带上一个小尾巴
比如

perl -e '
    BEGIN{
        $\ = "~";
    }
    for my $num (1..10){
        print "$num";
    }
'

# 输出
1~2~3~4~5~6~7~8~9~10~

就是说每次print,都会在print的内容后面加上$\指定的内容,这里是否想到减少按键盘的次数了。将$\赋值为\n。你自己多试一试哦。

后记

这一次并没有说参数相关的,而是说了这两个怪物,其实从第一篇再到这个第五篇,顺序是按照我个人认为的重要程度来述说的,有点主观啊!但是要是写的话就是说如果有一根线穿连着会不会更加有效一些。因为Perl特别擅长文本处理,而涉及到文本就不得不牵扯到换行啦,打印啦之类的。而这两个特殊变量就是与之相关的,虽然怪异但是这两个变量的确好用。对了,上面的例子都是搭配BEGIN{}和END{}搭配进行的全局的分隔符的设置,其实有时候可以使用local $/ = ">"local $\ = "\n",之类的写法来在局部块中进行设置。

相关

有关BEGIN{}END{}的说明已经在之前的内容中提到了。可以参见

引用

简笔画技法从新手到高手

    原文作者:白菜代码小推车
    原文地址: https://www.jianshu.com/p/a0a361c6daa4
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞