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