Perl One-Liners | Perl命令行學(xué)習(xí)5 $/和$\變量

Perl 特殊變量$/$\

上集回顧

上次我們看了一下-M-I這兩個(gè)搭檔
這次我們來(lái)看看這兩個(gè)特殊的”變量“$/$\,不是參數(shù)。

解釋

$/ : 輸入記錄分隔符
$\ : 輸出記錄分隔符

說(shuō)實(shí)話,這兩個(gè)符號(hào)的確是有些詭異!可以這么來(lái)記,“太陽(yáng)出來(lái)我爬山坡,爬上山坡我好唱歌”,爬坡的是/(入),下坡的是\(出)。

這兩個(gè)變量是特殊變量,什么意思呢?就是它們是從娘胎里來(lái)的,本來(lái)就有,不需要你去聲明,它們就在那里。

為什么要說(shuō)這兩個(gè)變量呢?這兩個(gè)變量是什么意思呢?下面先說(shuō)明一下這兩個(gè)奇特的怪物究竟是個(gè)什么玩意。

比如在工廠車間的流水線,生產(chǎn)罐頭的那種。

   [] [] [] [] [] [] [] [] [] [] [] []
->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->
| O  O  O  O  O  O  O  O  O  O  O  O  O  O  O  O |
<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<-
當(dāng)?shù)玫匠善饭揞^之后,需要裝箱了,可是多少個(gè)裝一箱呢。
這個(gè)時(shí)候就有機(jī)器負(fù)責(zé)控制履帶移動(dòng)的長(zhǎng)度來(lái)控制幾個(gè)罐頭為一組進(jìn)行裝箱(罐頭之間間距相等)。
比如4個(gè)罐頭裝一箱,那好,當(dāng)過(guò)了一定長(zhǎng)度之后傳送帶停下來(lái),機(jī)械臂將4個(gè)罐頭裝箱,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個(gè),怎么搞,好辦,設(shè)置一下傳送帶每次傳送的長(zhǎng)度就OK可
                          |===================      ---------
                          -                         | [] [] |
                         | |                        | [] [] |
                          |                         | [] [] |
                           [] [] [] [] [] []        ---------
->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->  #################### 
| O  O  O  O  O  O  O  O  O  O  O  O  O  O  O  O |  #################### 
<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<-  #################### 
有的時(shí)候廠家搞活動(dòng),在箱子里面除了有罐頭,還有小禮品喲。

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

^^^^^^^^^^
||||||||||
上面是一個(gè)裝罐頭的箱子,外面用繩子系了個(gè)禮物在外面,我怕我靈魂畫手的功力太深,你們認(rèn)不出來(lái)~~

這里不妨把perl的文本處理流程當(dāng)作是工廠中的流水線,每次讀取一“行”,來(lái)處理。

  • $/就是說(shuō)在什么地方將文本分隔開(kāi)來(lái)作為一組”罐頭“,類似于控制傳送帶移動(dòng)的長(zhǎng)度。
  • $\就是當(dāng)我想打印文本的時(shí)候后面帶的小尾巴是什么,就像是上面的小禮品一樣。

現(xiàn)實(shí)世界與機(jī)器世界

現(xiàn)實(shí)世界.JPG

機(jī)器世界.JPG

平常我們讀書,從左到右轉(zhuǎn)頭就是一行。但是在機(jī)器世界,究竟什么是“行”,其實(shí)計(jì)算機(jī)的存儲(chǔ)是連續(xù)的,并不是說(shuō)想現(xiàn)實(shí)世界那樣還轉(zhuǎn)行之類的。那么究竟是如何區(qū)分行與行呢?
比如有一段序列

ATGCGTAGCTA
TAGCTAGCTTG
AA

其實(shí)真實(shí)的是這樣的

ATGCGTAGCTA\nTAGCTAGCTTG\nAA

當(dāng)然了,更加還原是以1和0表示,這里為了方便敘述。也就是說(shuō)在這三“行”序列之間是用一個(gè)\n連起來(lái)的,并不是像現(xiàn)實(shí)世界轉(zhuǎn)頭之類的。機(jī)器為了區(qū)分,每次讀到\n,就知道了到了一“行”了。
上面兩張圖說(shuō)明了現(xiàn)實(shí)的書本紙和機(jī)器世界的區(qū)別LF就是指\n。這個(gè)就是為了告訴機(jī)器要“換行了”。那么這里Perl不僅可以要機(jī)器在\n的地方換行,也可以自己設(shè)置如果碰到什么字符那就換行,比如!、~@等等。

我之前有一個(gè)同學(xué)在處理文本的時(shí)候沒(méi)有將末尾的那個(gè)不可見(jiàn)的換行符去除,導(dǎo)致正則表達(dá)式無(wú)法匹配,也就無(wú)法得到正確結(jié)果,但是他換成從命令行輸出那一行信息卻可以匹配(從命令行讀取的不包含換行符)。一直糾結(jié),后來(lái)我給他說(shuō)了,他一直不相信,知道后來(lái)事實(shí)證明他沒(méi)搞清楚這個(gè)換行符。

額,可能被我搞的糊涂了,來(lái)看看例子就明白啦!

用法

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

這兩個(gè)就是變量,也就是說(shuō)可以直接對(duì)他們賦值

實(shí)例

  • 示例1
# 這次不用-a與-F參數(shù)來(lái)處理
echo "12-34-56,45-23-67,678-56-12" | perl -n -e '
    BEGIN{
        # 在讀取數(shù)據(jù)之前就設(shè)置好輸入記錄分隔符
        # 設(shè)置 , 作為“一行”的結(jié)尾的標(biāo)志
        $/ = ",";
    }
    # 在將讀取的每一“行”的一系列用 - 連起來(lái)的數(shù)值進(jìn)行分隔
    my @list = split /-/,$_;
    # 對(duì)每組數(shù)值求和
    my $total = 0;  # 初始化變量
    for my $num (@list){
        $total += $num;
    }
    print "$total\n";
'

# 輸出
102
135
746

這里來(lái)解釋一下

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

箭頭所指的就是每次讀取的”一行“的停止位置,平常我們一般都是認(rèn)為換行符才是一行的末尾,但是這里$/大哥說(shuō)了,機(jī)器人的世界中的天上天下的——換行,都?xì)w我管 。也就是說(shuō)這里它重新定義了行的概念,就是說(shuō),按照,來(lái)作為標(biāo)志。比如

機(jī)器讀
12-34-56,
這是”一行“
再讀
45-23-67,
這是”一行“
在讀
678-56-12
這是”一行“

這里的“行”是指機(jī)器讀的行

來(lái)點(diǎn)實(shí)際的東西

  • 示例2

假如有一個(gè)文件123.txt,內(nèi)容為

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

其實(shí)在平常我們碰到很多fasta文件,它的序列是按照80個(gè)堿基為一行就進(jìn)行了換行了,所以我們后續(xù)處理有些麻煩。比如我們想要得到名為atp1的序列,那么就是當(dāng)我判斷了到了atp1之后,接下來(lái)就是序列,可是只打印出>atp1下面的一行卻不是它的完整序列,還需要繼續(xù)打印,直到碰到>cox,這樣其實(shí)某種程度上來(lái)說(shuō)就有點(diǎn)不太方便。

怎么做呢?你根據(jù)今天說(shuō)的內(nèi)容應(yīng)該想出來(lái)怎么辦了吧!

# 使用 > 作為輸入分隔符
# 代碼如下
cat 123.txt | perl -n -e '
    BEGIN{
        $/ = ">";
    }
    # 由于是以 > 作為分隔符,那么尾巴處就可能有>符號(hào)(除了最后一行可能沒(méi)有其他都有)
    $_ =~ s/>$//;
    
    # 正則表達(dá)式中\(zhòng)s*\r*使因?yàn)椴恢恢涝赼tp1后面是否有空格和回車符,所以加上
    if($_ =~ m/^atp1\s*\r*\n/){
        # 1. 也可以在這里除去里面的換行符
        # print (substr($_,length($&)) =~ s/\r*\n//gr);
        # 2. 也可以不去除
        print ( substr($_,length($&) );
    }
'

# 輸出為
AGTCAGCTGACTCGATCTACGTCTAGCGACGT
GATACGTACGTACGGTACTCGTAGCTACCGTA
TAGTAGC

這里我把分隔出來(lái)的每一批字符寫一下

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

注意:由于這里我們對(duì)機(jī)器世界的行進(jìn)行了重新定義,在這每一“行”中就可能存在多個(gè)\n,而“行”的結(jié)尾就變成了>。

$\

這個(gè)參數(shù)就是說(shuō)當(dāng)輸出的時(shí)候,在輸出的內(nèi)容后帶上一個(gè)小尾巴
比如

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

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

就是說(shuō)每次print,都會(huì)在print的內(nèi)容后面加上$\指定的內(nèi)容,這里是否想到減少按鍵盤的次數(shù)了。將$\賦值為\n。你自己多試一試哦。

后記

這一次并沒(méi)有說(shuō)參數(shù)相關(guān)的,而是說(shuō)了這兩個(gè)怪物,其實(shí)從第一篇再到這個(gè)第五篇,順序是按照我個(gè)人認(rèn)為的重要程度來(lái)述說(shuō)的,有點(diǎn)主觀?。〉且菍懙脑捑褪钦f(shuō)如果有一根線穿連著會(huì)不會(huì)更加有效一些。因?yàn)镻erl特別擅長(zhǎng)文本處理,而涉及到文本就不得不牽扯到換行啦,打印啦之類的。而這兩個(gè)特殊變量就是與之相關(guān)的,雖然怪異但是這兩個(gè)變量的確好用。對(duì)了,上面的例子都是搭配BEGIN{}和END{}搭配進(jìn)行的全局的分隔符的設(shè)置,其實(shí)有時(shí)候可以使用local $/ = ">",local $\ = "\n",之類的寫法來(lái)在局部塊中進(jìn)行設(shè)置。

相關(guān)

有關(guān)BEGIN{}END{}的說(shuō)明已經(jīng)在之前的內(nèi)容中提到了??梢詤⒁?jiàn)

引用

簡(jiǎn)筆畫技法從新手到高手

版權(quán)聲明:本文采用 知識(shí)共享署名-非商業(yè)性使用-禁止演繹 4.0 國(guó)際許可協(xié)議 (CC BY-NC-ND 4.0) 進(jìn)行許可。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容