Perl基础速成
本文是针对没有Perl基础,但想用perl一行式命令取代grep/awk/sed的人,用于速学Perl基础知识。 Perl一行式系列文章:Perl一行式程序 perl的-e选项perl命令的-e选项后可以书写表达式,例如: perl -e 'print "hello worldn"' Perl中的函数调用经常可以省略括号,所以 在unix下建议使用单引号包围 如果表达式中有多个语句,各语句之间使用分号";"隔开。例如: perl -e 'print "hello";print "world"."n"' 注意,上面使用了点号"."来连接两个字符串。 稍后会解释另一个表达式选项"-E",它和"-e"功能几乎一样,唯一不同的是"-E"会自动启用一些高版本的功能。 print、printf、say和sprintfPerl中的print函数不会自动换行,所以需要手动加上"n"来换行。 perl -e 'print "hello world"' perl -e 'print "hello worldn"' Perl中的say()函数会自动换行,用法和print完全一致。但要使用say,需要使用use指定版本号高于5.010,。 $ perl -e 'use 5.010;say "hello world"' hello world 使用"-E"选项替换"-e",可以省略版本的指定,因为"-E"自动启用高版本功能。 $ perl -E 'say "hello world"' hello world Perl也支持printf函数,语法格式是 $ perl -e 'printf "hello %sn","Perl"' hello Perl sprintf()函数表示按照printf的方式进行格式化,然后保存起来。保存起来的内容可以赋值给变量。 $ perl -e '$a = sprintf "hello %sn","Perl";print "$a"' hello Perl 上面将格式化后的字符串 变量Perl中声明变量x需要使用 $x = "abc" $y = 33 ($x,$y)=("abc",33) ${var} = 333 # 加大括号是标准写法 下面是一行式命令中的变量使用示例: perl -e '$a="hello world";print "$an"' Perl中变量赋值时,总是会先计算右边的结果,再赋值给左边的变量。所以,变量交换非常方便: ($var1,$var2)=($var2,$var1) 对于一行式Perl程序,变量可以无须事先声明直接使用。 perl -e 'print $a + 1,"n"' 如果想要判断变量是否已经定义,可以使用 perl -e 'if(defined($a)){print $a,"n"}' 不带任何修饰的变量是全局变量,如果想要定义为局部变量,可以在变量前加上 my $a = "abc" 对于Perl一行式程序来说,几乎不需要考虑my。但及少数情况下需要使用大括号或其它语句块的时候,可以使用my来声明局部变量,出了语句块范围变量就失效。 $ perl -e ' $a = 33; { my $a = "abc"; print $a,"n"; } print $a,"n";' 数值、字符串和反斜线序列例如: 4 + 3 # 7 3.12 + 3.22 # 6.34 "4abc" + "3xyz" # 7 "abc" + "3xyz" # 3 "1.2abc" + "3.1x" # 4.3 1..6 # 1 2 3 4 5 6 1.2..6.4 # 1 2 3 4 5 6 需要解释下上面的几行语句。
字符串使用单引号或双引号包围,此外,Perl中也有反引号,这3种引用和shell中的单、双、反引号类似。:
$ perl -e '$a = `date +"%F %T"`;print $a' 2019-01-03 19:55:32 Perl中有以下几个常见的反斜线序列: n r t l # 将下个字母转换为小写 L # 将后面的多个字母都转换为小写,直到遇到E u # 将下个字母转换为大写 U # 将后面的多个字母都转换为大写,直到遇到E Q # 和E之间的所有字符都强制当作字面符号 E # L、U和Q的结束符号 字符串连接需要使用".",例如 Perl中数值和字符、字符串都支持自增、自减操作。相关示例参见Perl中的自增、自减操作。 q、qq和qx在Perl中,引号不一定非要写成符号,可以使用q()来表示单引号、qq()来表示双引号、qx()表示反引号。其中这里的括号可以替换成其它成对的符号,例如 使用q类型的引用可以避免在shell中一行式Perl程序的引号转义问题。 例如,在一行式Perl中想要保留单引号: $ perl -e "print q(abc'd)" 数组Perl中的数组本质上是一个列表(对于Perl一行式命令,可以将列表等价于数组),要声明数组,使用 @arr = ("Perl","Python","Shell") @{arr} = (1,2,3) # 加上大括号是标准的写法 @empty = () # 空数组 书写列表时,字符串需要使用引号包围,逗号分隔各个元素。还可以使用qw()来写列表,不需要再使用逗号分隔元素,而是使用空格,且每个元素都默认以单引号的方式包围。所以下面是等价的: @arr = qw(Perl Python Shell abcndef) @arr = ('Perl','Python','Shell,'abcndef') 对于一行式的perl命令,变量和数组可以直接使用而无需事先声明。 数组可以直接放在双引号中输出,默认输出的时候是用空格分隔各元素。 $ perl -e '@arr=qw(Perl Python Shell);print "@arrn"' Perl Python Shell 要取数组中的某个元素,使用 $ perl -e '@arr=qw(Perl Python Shell);print "$arr[1]n"' Python 数组 如果想要直接取得数组的个数,将数组赋值给一个变量或者使用scalar()函数即可。这涉及到Perl的上下文知识,不是本文内容,所以记住即可。 $ perl -e ' @arr = qw(Shell Perl PHP); $num = @arr;print "$numn"; print scalar @arr,"n";' 数组的索引可以是负数,-1表示最后一个元素,-2表示倒数第二个元素。所以 数组切片数组支持切片功能,切片操作使用 @arr = qw(Perl Python Shell Ruby PHP) @arr[0] # 取第一个元素形成一个新列表 @arr[1,1,-2] # 取两次第2个元素,一次第1个元素,一次倒数第2个元素形成新列表 @arr[1..3] # 以序列的方式取第2到第4个元素形成新列表 下面是一个示例: $ perl -e ' @arr=qw(Perl Python Shell Ruby PHP); print "@arr[1,-2]n"' Python Python Perl Ruby 如果想要取从第2个到倒数第2个元素,可以使用这种切片方式 $ perl -e '@arr=qw(Perl Python Shell Ruby PHP); print "@arr[1..$#{arr}-1]n"' Python Shell Ruby 操作数组相关函数数组可以使用pop/push函数来移除、追加最尾部的一个元素,使用shift/unshift函数移除、插入首部第一个元素。如果想要操作中间某个元素,可以使用splice()函数。这些函数的用法参见:增、删数组元素。 另外,还有sort()、reverse()函数,在Perl中sort太过强大,不适合在这里展开解释,所以记住它可以用来排序列表(数组)做简单使用即可。例如: $ perl -e ' @arr=qw(Perl Python Shell Ruby PHP); @arr1 = sort @arr; print "@arr1n"' PHP Perl Python Ruby Shell 对于sort还需注意的是,它不是在原地排序的,而是生成一个排序后的新列表,原数组中元素的顺序并不会受排序的影响。所以需要将这个新列表赋值给另一个数组变量才能得到排序后的结果,正如上面的示例一样。 但也有技巧可以直接输出排序后的结果,而且这个技巧非常有用: $ perl -e ' @arr=qw(Perl Python Shell Ruby PHP); print "@{ [ sort @arr ] }n"' PHP Perl Python Ruby Shell 这属于Perl的高级技巧,这里大致解释一下。它分成2个部分:
所以,当想要将某个操作的结果直接输出时,就可以采取这种方式: @{ [ something you do ] } 遍历数组要遍历数组,可以使用for、foreach、each,当然也可以使用while,只不过使用for/foreach/each要更方便。关于for/foreach/each/while详细的内容,见后文。 # foreach遍历数组 perl -e ' @arr=qw(Perl Python Shell Ruby PHP); foreach $i (@arr){print "$in"}' # for遍历数组:元素存在性测试遍历法 perl -e ' @arr=qw(Perl Python Shell Ruby PHP); for $i (@arr){print "$in"}' # for遍历数组:索引遍历法 perl -e ' @arr=qw(Perl Python Shell Ruby PHP); for($i=0; $i<=$#arr; $i++){print "$arr[$i]n"}' # each遍历数组:key/value遍历 perl -e ' @arr=qw(Perl Python Shell Ruby PHP); while (($index,$value) = each(@arr)){ print "$index: $valuen" }' 必须注意的是,Perl中for/foreach以元素存在性测试遍历时,控制变量 $ perl -e ' @arr=qw(Perl Python Shell Ruby PHP); for $i (@arr){$i = $i."X"}; # 为每个元素加尾随字符"X" print "@arrn"' PerlX PythonX ShellX RubyX PHPX split()和join()函数join()用于将列表连接成字符串,split()用于将字符串分割成列表。 join $sep,$list split /pattern_sep/,$string,limit 详细用法和示例参见:Perl处理数据(一):s替换、split和join。下面是两个简单示例: print join "--",a,b,c,d,e; # 输出"a--b--c--d--e" $str="abc:def::1234:xyz"; @list = split /:/,$str; 上面的字符串分割后将有5个元素:abc,def,空,1234,xyz。 hash(关联数组)Perl也支持hash数据结构,hash结构中key/value一一映射,和Shell中的关联数组是一个概念。 在Perl中,无论是数组还是hash结构,本质都是列表。所以下面的列表数据可以认为是数组,也可以认为是hash,关键在于它赋值给什么类型。 ("name","longshuai","age",23) 在Perl中,数组类型使用 所以,下面的表示hash结构: %Person = ("name",23) %Person = qw(name longshuai age 23) 列表作为hash结构时,每两个元素组成一个key/value对,其中key部分必须是字符串类型。所以上面的hash结构表示的映射关系为: %Person = ( name => "longshuai",age => 23,) 实际上,上面使用胖箭头 hash数据不能在双引号中进行内容替换,可以直接输出它,但直接输出时hash的元素是紧挨在一起的,这表示hash的字符串化。 $ perl -e ' %hash = qw(name longshuai age 23); print "%hash","n"' %hash $ perl -e ' %hash = qw(name longshuai age 23); print %hash,"n"' age23namelongshuai 从hash中取元素使用 $ perl -e ' %hash = (name=>"longshuai",age=>23); print "$hash{name}","n"' longshuai $ perl -e ' %hash = (name=>"longshuai",age=>23); print "@hash{name,name,age,age}","n"' longshuai longshuai 23 23 hash相关函数主要有keys()、values()、exists()和delete()。
下面是keys和values函数的示例。 $ perl -e ' %hash = (name=>"longshuai",age=>23); print "keys:n"; print keys %hash,"n"; print "values:n"; print values %hash,"n";' keys: agename values: 23longshuai 看起来不是很爽,所以赋值给数组再来输出。 $ perl -e ' %hash = (name=>"longshuai",age=>23); @keys = keys %hash; @values = values %hash; print "=========n"; print "@keysn"; print "=========n"; print "@valuesn";' ========= age name ========= 23 longshuai 如何知道hash结构中有多少个key/value对?是否记得将数组(列表)赋值给一个变量时,得到的就是它的个数? $ perl -e ' %hash = (name=>"longshuai",age=>23); $nums = keys %hash; print "$numsn";' 2 如果想要直接输出个数而不是先赋值给变量,可以对一个列表使用函数scalar(),它会强制让Perl将列表当作标量(变量): $ perl -e ' %hash = (name=>"longshuai",age=>23); print scalar keys %hash,"n";' 2 如何排序hash结构?只需对keys的结果应用sort/reverse函数,再进行遍历输出即可。 $ perl -e ' %hash = (name=>"longshuai",age=>23); for $key (sort keys %hash){ print "$key => $hash{$key}n"; }' age => 23 name => longshuai 遍历hash要遍历hash结构,可以使用while + each或者for/foreach遍历hash的key或value。 # 使用while + each $ perl -e ' %hash = (name=>"longshuai",age=>23); while(($key,$value) = each %hash){ print "$key => $value","n" }' name => longshuai age => 23 # 使用for或foreach去遍历keys或values $ perl -e ' %hash = (name=>"longshuai",age=>23); for $key (keys %hash){ print "$key => $hash{$key}","n" }' age => 23 name => longshuai 默认变量$_、@ARGV、@_在Perl中,有一个非常特殊的变量 当没有为函数指定参数时、表达式中需要变量但却没给定时都会使用这个默认变量 例如: perl -e '$_="abcn";print' print函数没有给参数,所以默认输出 再例如,for/foreach的遍历行为: for $i (@arr){print "$in"} for (@arr){print "$_n"} for本该需要一个控制变量指向 用到默认变量的地方很多,没法列出所有使用
$ perl -e ' $name = shift; $age = shift; print "$name:$agen"' longshuai 23 默认数组(列表)变量对一行式perl命令来说可能遇不上,所以了解一下足以,只要能在需要的时候看懂即可。 布尔值判断在Perl中,真假的判断很简单:
注意,Perl中没有true和false的关键字,如果强制写true/false,它们可能会被当作字符串,而字符串为真,所以它们都表示真。例如下面的两行,if的测试对象都认为是字符串而返回真。 perl -e "if(true){print "aaaan"}" perl -e "if(false){print "aaaan"}" 大小比较操作Perl的比较操作符和bash完全相反。数值比较采用符号,字符串比较采用字母。 数值 字符串 意义 ----------------------------- == eq 相等 != ne 不等 < lt 小于 > gt 大于 <= le 小于或等于 >= ge 大于或等于 <=> cmp 返回值-1/0/1 最后一个
对于 几个示例: 35 != 30 + 5 # false 35 == 35.0 # true '35' eq '35.0' # false(str compare) 'fred' lt 'bay' # false 'fred' lt 'free' # true 'red' eq 'red' # true 'red' eq 'Red' # false ' ' gt '' # true 10<=>20 # -1 20<=>20 # 0 30<=>20 # 1 逻辑运算Perl支持逻辑与( 符号类型的逻辑操作 ($a > $b) && ($a < $c) $a > $b and $a < $c Perl的短路计算非常特别,它返回的是最后运算的表达式的值。也就是说,它有返回值,通过返回值可以判断短路计算的布尔逻辑是真还是假。
所以,这个返回值既保证短路计算的结果不改变,又能得到返回值。这个返回值有时候很有用,例如,可以通过逻辑或的操作来设置默认值: $name = $myname || "malongshuai" 上面的语句中,如果 但上面有一种特殊的情况,如果 这和预期有所冲突,这时可以使用 $name = $myname // "malongshuai" 所以,就算 流程控制if、unless和三目运算逻辑语法格式: # if语句 if(TEST){ ... } elsif { ... } else{ ... } # unless语句 unless(TEST){ ... } # 三目运算符 expression ? if_true : if_false if表示TEST为真的时候,执行后面的语句块,否则执行elsif或else语句块。 unless则相反,TEST为假的时候,执行后面的语句块。也就是等价于 注意TEST部分,只要它的结果在布尔逻辑上是真,就表示真。例如: if("abc"){} # 真 if(0){} # 假 if(0 > 1){} # 假 where和until循环语法: while(CONDITION){ commands; } until(CONDITION){ commands; } Perl的until和其它某些语言的until循环有所不同,Perl的until循环,内部的commands主体可能一次也不会执行,因为Perl会先进行条件判断,当条件为假时就执行,如果第一次判断就为真,则直接退出until。 for和foreach循环Perl中的for循环和Bash Shell类似,都支持两种风格的for: # (1).C语言风格的for for(expr1;expr2;expr3){...} for($i=0;$i<100;$i++){...} # (2).元素存在性测试的for for $i (LIST){...} # (3).元素存在性测试的for等价于foreach foreach $i (LIST){...} 对于第一种for语法(即C语言风格的for),3个部分都可以省略,但分号不能省略:
例如下面将3个部分全都省略,将会无限循环: for(;;){ print "never stop"; } 对于(2)和(3)的元素存在性测试的循环,用来迭代遍历列表,每次迭代过程中通过控制遍历
例如: $ perl -e ' @arr = qw(Perl Shell Python Ruby PHP); for (@arr){ $_ = $_."x"; } print "@arrn"' Perlx Shellx Pythonx Rubyx PHPx 上面没有显式指定控制变量,所以采用默认变量 表达式形式的流程控制语句Perl支持单表达式后面加流程控制符。如下: command OPERATOR CONDITION; 例如: print "true.n" if $m > $n; print "true.n" unless $m > $n; print "true.n" while $m > $n; print "true.n" until $m > $n; print "$_n" for @arr; print "$_n" foreach @arr; 书写时,很多时候会分行并缩进控制符: print "true.n" # 注意没有分号结尾 if $m > $n; 改写的方式几个注意点:
改写的方式不能满足需求时,可以使用普通的流程结构。 大括号:运行一次的语句块使用大括号包围一段语句,这些语句就属于这个语句块。这个语句块其实是一个循环块结构,只不过它只循环一次。语句块有自己的范围,例如可以将变量定义为局部变量。 $ perl -e ' $a = 33; { my $a = "abc"; print $a,"n";' do语句块do语句块结构如下: do {...} do语句块像是匿名函数一样,没有名称,给定一个语句块,直接执行。do语句块的返回值是最后一个执行的语句的返回值。 例如,if-elsif-else分支结构赋值的语句: if($gender eq "male"){ $name="Malongshuai"; } elsif ($gender eq "female"){ $name="Gaoxiaofang"; } else { $name="RenYao"; } 改写成do语句块: $name=do{ if($gender eq "male"){"Malongshuai"} elsif($gender eq "female") {"Gaoxiaofang"} else {"RenYao"} }; # 注意结尾的分号 前面说过,表达式形式的流程控制语句控制符左边只能是一个命令。例如: print $_+1,"n";print $_+2,"n" if $_>3; # 等价于下面两条语句: print $_+1,"n"; print $_+2,"n" if $_>3; 使用do语句块,可以将多个语句组合并当作一个语句。例如: do{print $a+1,"n";print $a+2,"n"} if $a>3;
不要把do和大括号搞混了,大括号是被解释的语句块范围的语法符号,可以用来标记自己的作用域范围。但 last/next/redo/continue
熟悉sed的人肯定很容易理解这里redo和continue的作用。sed默认情况下会输出每一行被处理后的内容,这是因为它有一个和这里continue一样的逻辑,在perl命令的"-p"选项也一样,到时候会解释这个continue的逻辑。sed的"-D"选项则是处理后立即回到sed表达式的顶端再次对模式空间进行处理,直到模式空间没有内容,这实现的是redo的逻辑。 BEGIN/END语句块Perl像awk一样,也有BEGIN和END语句块,功能和awk是一样的。实际上Perl除了BEGIN/END,还有CHECK、INIT和UNITCHECK语句块,不过对于一行式Perl程序,BEGIN/END就足够了。 Perl命令行参数和ARGVperl命令行的参数存放在数组ARGV(@ARGV)中,所以可以访问 $ perl -e 'print "@ARGVn"' first second first second 不难看出, 其实ARGV数组有点特别,如果参数中有被读取的文件参数,那么每开始读一个文件,这个文件就从ARGV数组中剔除。所以,在程序编译期间(BEGIN语句块),ARGV数组中包含了完整的参数列表,处理第一个参数文件时,ARGV数组中包含了除此文件之外的其它参数列表,处理第二个参数文件时,ARGV数组中继续剔除这个文件参数。 例如,perl一行式命令中,"-p"选项会输出参数文件的每一行被处理后的数据,也就是说它会读取参数文件。 $ echo aaaa > a.txt $ echo bbbb > b.txt $ perl -pe ' BEGIN{ print "in BEGIN:n"; print "@ARGVn" } print "in argv file: @ARGVn"; END{ print "in END:n"; print "@ARGVn" } ' a.txt b.txt 输出结果: in BEGIN: a.txt b.txt in argv file: b.txt aaaa in argv file: bbbb in END: 其实,除了ARGV数组 例如: $ echo aaaa > a.txt $ echo bbbb > b.txt $ perl -pe ' BEGIN{ print "in BEGIN:n"; print "@ARGVn" } print "reading me: $ARGVn"; ' a.txt b.txt 输出结果: in BEGIN: a.txt b.txt reading me: a.txt aaaa reading me: b.txt bbbb 和shell交互:执行shell命令perl可以直接执行shell中的命令方式有3种,但这里只介绍两种:反引号(或qx)、system()函数。 反引号反引号 perl -e '$datetime = qx(date +"%F %T");print $datetime' 需要注意的是,反引号执行的结果中一般都会保留尾随换行符(除非像printf一样明确不给尾随换行符),所以在print这些变量的时候,可以不用指定"n"。或者为了保持同意,使用chomp()或chop()函数操作变量,去掉最后一个字符。 $ perl -e ' $datetime = qx(date +"%F %T"); chop $datetime; # 或chomp $datetime print "$datetimen";' 还可以更简便一些,直接在赋值语句上chop或chomp: $ perl -e ' chop($datetime = qx(date +"%F %T")); print "$datetimen";' system()第二种和shell交互的方式是system()函数。它会直接输出所执行的命令,而不是将命令的结果作为返回值。所以,system()函数不应该赋值给变量。 system()要执行的命令部分需要使用引号包围。而对于一行式perl程序来说,直接使用引号是一个难题,所以可以考虑使用qq()、q()的方式。例如: $ perl -e ' system q(date +"%F %T");' 2019-01-03 20:18:34 如果一定想要将system()的结果赋值给变量,得到的赋值结果是system()的返回值,而它的返回值表示的是命令是否成功调用(严格地说是wait()的返回值)。 $ perl -e ' $datetime = system q(date +"%F %T"); print "$datetimen";' 2019-01-03 20:23:21 0 还可以使用shell的管道、重定向等功能: $myname="Malongshuai"; system "echo $myname >/tmp/a.txt"; system "cat <1.pl"; system 'find . -type f -name "*.pl" -print0 | xargs -0 -i ls -l {}'; system 'sleep 30 &'; system()的用法其实很复杂,如果上面简单使用单引号包围无法解决问题时,可以参考Perl和操作系统交互(一):system、exec和反引号,这里面对system()的参数做了非常透彻的分析。 和shell交互:向perl命令行传递来自shell的数据对于一行式命令,可能会想要将shell的变量、shell中命令的执行结果通过变量传递给perl命令。本人收集了几种方式,也许不全,但应该足够应付所有情况。 方式一:通过环境变量 perl程序在运行时,会自动注册一个hash结构 $ perl -e 'print "$ENV{PATH}n"' $ perl -e 'print "$ENV{SHELL}n"' 所以,想要获取shell的变量,可以先将其导出为环境变量,再从 $ export name="longshuai" $ perl -e 'print "$ENV{name}n"' 方式二:将perl -e ‘xxxx‘的单引号拆开重组,直接将需要被shell解析的东西暴露给shell去解释 $ name=longshuai $ perl -e 'print "'$name'n"' longshuai 上面分成三部分 这种方式需要对shell的引号解析非常熟练,对sed来说这种写法有时候是必要的,因为这是sed和shell交互的唯一方式,但对于perl命令行来说,没有必要这样写,因为可读性太差,且很难写,一般人真的不容易写不来。 方式三:将变量放入参数位置,使其收集到ARGV数组中,然后在perl表达式中shift这些数据 $ name=longshuai $ age=23 $ perl -e ' $name = shift; $age = shift; print "$name,$agen"' $name $age longshuai,23 注意上面的shift没有给定参数,所以shift会使用默认变量。由于shift期待的操作对象是一个数组(列表),且不是在子程序内部(子程序内部表示在sub语句块内),所以使用默认数组 $ perl -e ' $name = shift @ARGV; $age = shift @ARGV; print "$name,$agen"' $name $age 方式四:使用perl -s选项 perl的-s选项允许解析 $ perl -e 'xxxxx' -- -name=abc -age=23 a.txt b.txt 从 例如: $ perl -se ' print "ARGV: @ARGVn"; print "NAME & AGE: $name,$agen"; ' -- -name="longshuai" -age=23 abc def ARGV: abc def NAME & AGE: longshuai,23 上面传递的参数是 方式五:杜绝使用shell,完全替代为perl。在perl中反引号或qx()也支持运行shell程序 例如: $ name=longshuai $ perl -e ' $name = qx(echo $name); print "name in perl: $name"' name in perl: longshuai $ perl -e ' $time = qx(date +"%T"); print "time in perl: $time"' time in perl: 19:52:39 注意上面 Perl读写文件一行式perl程序的重头戏自然是处理文本数据,所以有必要解释下Perl是如何读、写数据的。 读取标准输入<STDIN>
$ perl -e '$name=<STDIN>;print "your name is: $name";' longshuai # 这是我输入的内容 your name is: longshuai # 这是输出的内容 因为读取的是标准输入,所以来源可以是shell的管道、输入重定向等等。例如: $ echo "longshuai" | perl -e '$name=<STDIN>;print "yourname is: $name";' your name is: longshuai 在比如,判断行是否为空行。 $ perl -e ' $line=<STDIN>; if($line eq "n"){ print "blank linen"; } else { print "not blank: $line" }' 注意, # 每次只读一行 $ echo -e "abcndef" | perl -e '$line=<STDIN>;print $line;' abc # 每次迭代一行 $ echo -e "abcndef" | perl -e 'while(<STDIN>){print}' abc def # 一次性读取所有行保存在一个列表中 $ echo -e "abcndef" | perl -e 'print <STDIN>' abc def 另外需要注意的是,如果将 $ echo -e "abcndef" | perl -e '@arr=<STDIN>;print "@arr"' abc def 解决办法是执行一下chomp()或chop()操作,然后在输出时手动指定换行符。 $ echo -e "abcndef" | perl -e '@arr=<STDIN>;chomp @a;print "@arrn"' abc def 读取文件输入<>使用两个尖括号符号 例如读取并输出/etc/passwd和/etc/shadow文件,只需将它们放在表达式的后面即可: $ perl -e ' while(<>){ print $_; # 使用默认变量 }' /etc/passwd 可以直接在perl程序中指定ARGV数组让 perl -e '@ARGV=qw(/etc/passwd);while(<>){print}' 一般来说,只需要 例如,下面的代码表示读取每一行,但如果行首以字符串abc开头,则马上读取下一行。 perl -e ' while(<>){ if($_ =~ /^abc/){ <>; } ... }' 文件句柄其实 打开文件以供读取的方式为: open FH,"<","/tmp/a.log" open $fh,"/tmp/a.log" # 与上面等价 文件句柄名一般使用大写字母(如FH)或者直接使用变量(如$fh)。 然后读取即可: while(<FH>){...} while(<$fh>){...} 例如: $ perl -e 'open FH,"/etc/passwd";while(<FH>){print}' 除了打开文件句柄以供读取,还可以打开文件句柄以供写入: open FH1,">","/tmp/a.log"; # 以覆盖写入的方式打开文件/tmp/a.log open FH2,">>","/tmp/a.log"; # 以追加写入的方式打开文件/tmp/a.log 要写入数据到文件,直接使用print、say、printf即可,只不过需要在这些函数的第一个参数位上指定输出的目标。默认目标为STDOUT,也就是标准输出。 例如: print FH1,"hello worldn"; say FH,"hello worldn"; printf FH1,"hello worldn"; 在向文件句柄写入数据时,如果使用的是变量形式的文件句柄,那么print/say/printf可能会无法区分这个变量是文件句柄还是要输出的内容。所以,应当使用 print {$fh},"hello worldn"; 正则表达式匹配和替换本文通篇都不会深入解释Perl正则,因为内容太多了,而且我已经写好了一篇从0基础到深入掌握Perl正则的文章Perl正则表达式超详细教程以及 对于学习perl一行式程序来说,无需专门去学习Perl正则,会基础正则和扩展正则足以。虽不用专门学Perl正则,但有必要知道Perl的正则是如何书写的。 使用
所以要匹配/替换内容,有以下两种方式:
匹配Perl中匹配操作返回的是匹配成功与否,成功则返回真,匹配不成功则返回假。当然,Perl提供了特殊变量允许访问匹配到的内容,甚至匹配内容之前的数据、匹配内容之后的数据都提供了相关变量以便访问。见下面的示例。 例如: 1.匹配给定字符串内容 $ perl -e ' $name = "hello gaoxiaofang"; if ($name =~ m/gao/){ print "matchedn"; }' 或者,直接将字符串拿来匹配: "hello gaoxiaofang" =~ m/gao/; 2.匹配来自管道的每一行内容,匹配成功的行则输出 while (<STDIN>){ chomp; print "$_ was matched 'gao'n" if /gao/; } 上面使用了默认的参数变量 以下是执行结果: $ echo -e "malongshuaingaoxiaofang" | perl -e " while (<STDIN>){ chomp; print qq($_ was matched 'gao'n) if /gao/; }" gaoxiaofang was matched 'gao' 3.匹配文件中每行数据 while (<>){ chomp; if(/gao/){ print "$_ was matched 'gao'n"; } } 替换
$str = "ma xiaofang or ma longshuai"; $str =~ s/ma/gao/g; print "$strn";
if(s/reg/rep/){ print "$_n"; } print "$_n" if s/reg/rep/ while(s/reg/rep/){ ... } 如果想要直接输出替换后得到的字符串,可以加上 $ perl -e ' $str = "ma xiaofang or ma longshuai"; print $str =~ s/ma/gao/gr,"n";' gao xiaofang or gao longshuai (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |