perl一行式程序系列文章:Perl一行式html
本文用來收集Perl一行式中涉及到的一些選項、特殊變量的說明,能夠用來作速查手冊。express
本文會逐漸更新。數組
第一次學Perl一行式時,請直接忽略本文內容,並直接從後面的示例部分開始看。本文會在每個示例中解釋出現的選項、變量、函數和語法。函數
perl一行式語法:spa
perl [-0aFlimMnps] -e 'EXPRESSION' ARGUMENTS perl [-0aFlimMnps] -E 'EXPRESSION' ARGUMENTS
其中"-e"或"-E"選項用於指定待運行的表達式,它們之間的不一樣點在於"-E"會自動啓用高版本功能特性,例如能夠直接使用say()函數而無需先use 5.010;
。命令行
能夠指定多個-e/-E,但使用多個的時候,注意每一個表達式後面的';'結尾符號,不然語法報錯。code
這兩個選項都表示按照隱含的邏輯直接處理表達式後面的參數表明的文件。若是perl -e
命令行中沒有這兩個選項,則只能本身在-e表達式中編寫讀取文件、處理數據、輸出/刪除的代碼邏輯。htm
-n選項使得perl單行命令以相似於以下代碼的方式運行:對象
LINE: while(<>){ ...-e expression CODE HERE... }
因爲while中使用的是<>
,因此它會從@ARGV
中讀取參數文件進行處理。blog
perl -n
就像sed -n
同樣,表示禁止默認的輸出。若是想要強制輸出,只能在-e表達式中自行指定輸出操做,例如print/say/printf。
-p選項使得perl單行命令以相似於以下代碼的方式運行:
LINE: while(<>){ ...-e expression CODE HERE... }continue{ print or die "-p destination: $!\n"; }
perl -p
用於強制輸出$_
,它會覆蓋-n選項。
必需要注意的是-n和-p都採用<>
來讀取文件,而它從文件中讀取每一行時會保留每一行的尾隨換行符"\n"。
-p和-n的邏輯雖然很簡單,也如sed的-n和p命令相似,但對於初學perl一行式程序的人來講,仍然很容易迷惑,由於Perl是一門語言,perl一行式也同樣能夠寫成一門簡單的語言,這意味着幾乎老是有多種一行式的方式實現一個需求。
例如,-p能夠被-n + print
替代,-n、-p均可以被-e中的while(<>)
替代。
但既然perl一行式提供了-n和-p的選項,寫perl一行式的時候天然應該追求精簡化,讓-e表達式的代碼邏輯更簡單。
根據我我的的總結:
$_
,例如對$_
的賦值、s替換,此時不須要額外的print,但有些操做是能夠隱藏$_
的,最多見的就是s替換命令-l -lOCTNUM
選項開啓自動行尾處理功能。它有兩個過程:
$\
設置爲OCTNUM的八進制數值,OCTNUM的ASCII字符將追加在輸出的每一行行尾。若是省略了OCTNUM,則將$\
設置爲輸入行分隔符變量$/
的值,一般是換行符須要注意的是,省略OCTNUM的時候,也就是隻有-l的時候,會在處理這個選項的那一刻就完成$\ = $/
的賦值,因此對於-ln0e EXPRESSION
將進行兩段賦值:
# 處理-l的時候 $\ = $/; # 處理-0的時候 $/ = \0;
這使得輸出行分隔符取輸入行分隔符的值,並在以後修改輸入行分隔符。
注意上面的-0選項不能直接放在-l選項後(也就是-l0ne
),這會產生歧義,認爲0是-l選項的參數值,而不是-0選項。
通常來講,"-l"選項是用來爲print函數追加換行符的,因此"-l"常常結合-n選項一塊兒使用。例如:
$ perl -lne 'print' file.log
設置輸入行分隔符$/
:
-0[octal/hexadecimal]
-0
使得perl讀取行時,以\0
做爲行輸入分隔符,也就是對行輸入分隔符變量$/
進行賦值:$/ = "\0";
若是沒有給定任何選項參數,則表示設置爲null,即等價於$/ = undef
,這表示一次性從文件頭部一直讀取到文件尾部看成一行。
若是給定了OCTNUM,即\0OCTNUM
,則將八進制數值OCTNUM對應的ACSII做爲行輸入分隔符。
特別地,設置-00
表示將$/
設置爲空"",即$/ = ""
,這表示按段落讀取到$_
且壓縮連續空行。
-a
選項打開自動分割模式,只能在-n或-p模式下使用。
-a使得-n或-p的while循環中首先對行進行一次隱含的split分割操做,並將分割後的結果放進數組@F
中,使其能夠成爲一個個的字段,並經過$F[n]
的方式調用各字段,其中n爲字段的索引號,從0開始計算。
分割後的元素全都收集到一個數組@F
中,因此第一個字段的內容是$F[0]
,最後一個字段是$F[-1]
或$F[$#F]
。
若是想取多個字段,能夠對數組@F
進行切片,例如第3個字段和第第5個字段@F[2,4]
,第3個字段到倒數第二個字段是@F[2..$#F-1]
或@F[1..~~@F-2]
。不要忘記,$_
這時表示整行,相似於awk裏的$0
,而Perl中的$0
表示的是程序名稱(對於perl一行式,$0
的值爲-e
或-E
)。
經過-a選項,可使perl單行程序能夠以相似於awk的方式運行,只不過awk的第一個字段是從$1
開始的,而-a的第一個字段是從$F[0]
開始的。
-a劃分字段的分隔符由-F選項指定。若是沒有指定-F,則默認以空白符號進行分割(連續空格被認爲是單空格)。
可使用-Fpattern
指定字段分隔符,也就是做爲split的第一個參數。pattern能夠被雙斜線//
、單引號''
或雙引號""
包圍,若是沒有給定符號,則默認使用單引號。
-F: -F/:/ -F":" -F':'
關於-F的pattern,普通的字符直接包圍便可,但想要指定空白符號做爲分隔符,必須注意官方手冊中的一句話:You can't use literal whitespace or NUL characters in the pattern
,也就是說不容許直接指定空白符號做爲分隔符。
實際上-Fpattern
能夠替換爲split /pattern/;
。因此想要指定空白符號做爲分隔符,別用-F,而是直接使用split函數:
$ perl -alne 'split / /;print $F[1]' file.log
此外,空白符號可使用\s
來替代:
$ perl -F'\s+' -alne 'print $F[-1]' file.log
-i[extension]
這個選項和sed的-i選項功能同樣,都是爲了提供副本或原地修改。
若是不指定extension,則perl打開一個臨時文件的文件句柄做爲print的輸出對象,處理完成後將此臨時文件重命名爲原始文件名。因此,原始文件會被刪除,且原始文件的寫權限不影響"-i"選項的重命名,只有文件所在目錄的寫權限才能限制"-i"建立新文件。
若是指定了extension,則表示拷貝原文件爲一個新的文件名,而後原始的文件名做爲print的輸出對象。例如-i'.bak'
表示拷貝原始文件並命名爲"FILENAME.bak",而後原始的文件名FILENAME是perl的輸出目標。也就是說,操做完成後,FILENAME是被修改的,FILENAME.bak是未作修改的原始內容。
若是extension中沒有包含*
,則字符做爲原文件名的後綴,例如-i".bak"
。若是extension中包含了*
,則每一個*
都表明原始文件名,這使得能夠給文件加前綴、後綴等。例如-i"file-*-1-*.bak"
將命名爲file-FILENAME-1-FILENAME.bak
。
這兩個選項用來導入模塊。
-mmodule -Mmodule -M'module ...' -[mM]module=arg[,arg]...
-m
導入模塊時,至關於執行了use module ();
,這表示在程序中必須使用完整的名稱來引用模塊中的屬性。例如-m'List::Util'
時,在-e表達式中要使用其max函數,須要指定爲List::Util::max @arr
。
-M
導入模塊時,至關於執行了use module;
,這時要使用模塊中的屬性仍然須要些完整的名稱。但-M
還支持額外的參數。例如-M'List::Util qw(max sum)'
表示導入List::Util
模塊中的max和sum函數,這時在-e表達式中能夠直接使用這兩個函數名,而無需寫完整的名稱List::Util::max @arr
。
對於-m和-M,還有另外一種"="的寫法,這種寫法使得-m和-M沒有任何的區別。例如
-m'List::Util=sum,max'
和-M'List::Util=sum,max'
是等價的,它們都表示導入這List::Util
模塊中的sum和max函數,使得使用這兩個函數的時候無需再寫完整名稱。
perl的-s選項容許解析--
以後的-xxx=yyy
格式的開關選項。
$ perl -e 'xxxxx' -- -name=abc -age=23 a.txt b.txt
從--
以後的參數,它們本該被收集到ARGV中,但若是開啓了-s選項,這些參數部分若是是-xxx=yyy
格式的,則被解析成perl的變量$xxx
併爲其賦值yyy,而那些不是-xxx=yyy
格式的參數則被收集到ARGV數組中。
例如:
$ perl -se ' print "ARGV: @ARGV\n"; print "NAME & AGE: $name,$age\n"; ' -- -name="longshuai" -age=23 abc def ARGV: abc def NAME & AGE: longshuai,23
上面傳遞的參數是-name="longshuai" -age=23 abc def
,由於開啓了-s選項,因此解析了兩個perl變量$name=longshuai $age=23
,另外兩個abc def
則被收集到ARGV數組中。
$\
表示print函數的輸出行分隔符。默認爲undef,因此print默認輸出時兩端數據老是連在一塊兒的。
能夠指定爲換行符"\n",這樣print輸出每段數據都會自帶換行符。
$ perl -e '$\ = "\n";print "haha"' haha
但必須注意,對於perl一行式程序的-p選項,它經過<>
讀取數據時會保留每一行的尾隨換行符(除非在-e表達式中使用了chomp/chop),這時不該該額外設置$\ = "\n"
,不然每行後面都會多輸出一空行。
$/
表示讀取文件時的輸入行分隔符,默認爲換行符"\n"。在讀取文件的時候,經過該特殊變量能夠控制如何分行。
能夠設置爲多個字符。
若是設置爲undef,表示一次性從文件頭一直讀取到文件尾看成一行。
若是設置爲空""或"\n\n",表示按段落讀取。不一樣的是:
$.
$.
表示當前處理的行的行號。
實際上,它表示的是當前正在被打開的文件句柄的行號計數器。只要文件句柄不顯式關閉,行號計數器就不會重置(open的隱式關閉以及reopen都不會重置)。
<>
讀取ARGV文件時從不關閉文件句柄,因此在一行式perl程序中使用了-n/-p時,多個參數文件的行號是連續下去而不會重置的。
若是確實想要重置<>
所讀取的每一個文件的行號,能夠經過eof函數來判斷,在到了文件底部的時候就關閉當前處理的文件。
while(<>){ print "$. $_\n"; } continue { close(ARGV) if eof #注意,不是eof() }
例如:
$ perl -e 'while(<>){print "$. $_"} continue {close(ARGV) if eof}'
eof和eof()是不一樣的,前者判斷每一個文件的文件尾部,後者則判斷最後一個文件的尾部(也就是無內容可讀了)。因此,下面的表示在最後一個文件的前面插入一行分割線。
while(<>){ print "-" x 30,"\n" if eof(); print "$. $_" }
@F
是"-a"選項將行自動分割後,各字段所保存的數組容器。具體參見-a選項。
$,
和$"
$,
變量指定print/say輸出無雙引號包圍的列表/數組時的元素分隔符,默認值爲undef,也就是元素之間牢牢相連。
$"
變量指定print/say輸出雙引號包圍時的列表/數組時的元素分隔符,默認值爲空格。
$ perl -le '@arr=qw(Shell Perl Python);print @arr' ShellPerlPython $ perl -le '@arr = qw(Shell Perl PHP);print "@arr"' Shell Perl PHP
指定特殊變量$,
或$"
的值:
$ perl -le ' @arr=qw(Shell Perl Python); $,=" "; print @arr' Shell Perl Python $ perl -le ' @arr=qw(Shell Perl Python); $"=":"; print "@arr"' Shell:Perl:Python