# 有选择的打印或者删除行 ## 85.打印文件的首行(模仿head -1) perl -ne 'print; exit' 本行代码迄今为止最简单一个。此处由于使用-n参数Perl读了第一行到$_,接着调用print语句输出 $_变量的内容。接着推出。就这样,第一行就被打印出来了,而这恰好就是我们需要的。 ## 86.打印文件开始的10行(模仿head -10) perl -ne 'print if $. <= 10' 本行代码是使用了$.特殊变量。这个变量带包“当前行序号”。每次Perl读下一行的时候,$.的值为自动加一。因此本行代码非常好理解:当行序号等于或者小于10的时候,打印出行内容。 本行代码也可以用不带if语句的方法: perl -ne '$. <= 10 && print' 此处,只有当$.<=10布尔表达式为true时执行打印语句,而只有行号小于或者等于10时候表达式为真。 ## 87.打印最后一行(模仿tail -1) perl -ne '$last = $_; END { print $last }' 打印最后一行的代码需要一点技巧,因为你一直需要把前一行保存在内存里。本行代码总我们一直把当前行保存到$last变量。当Perl代码结束时候,总会执行END块的。现在当读完最后一行,执行END块,退出的时候,我们打印出$last变量,这就是最后一行的内容。 另外一种同样同能代码是, perl -ne 'print if eof' 本行代码使用eof函数,这个函数在下一次读到文件的末尾时候返回1。由于读到文件最后一行的时候,下一行读(文件末尾)返回eof为真,所以本代码作出了我们期望所做的事情。 ## 88.打印文件的最后10行(模拟tail -10) perl -ne 'push @a, $_; @a = @a[@a-10..$#a]; END { print @a }' 这个有点复杂。此处我们把每一行都put到数组@a中,然后用他的数组切片代替他。我们做 @a = @a[@a-10..$#a],这表示用@a的最后10个元素取代他自己。@a-10在标量上下文被估值,他返回值为数组元素个数减10。#$a是@a数组的最后一个下标。@a[@a-10..#$a]取得了数组的最后10个元素的下标,所以@a保存了最后10个元素。 举例子假设数组@a保存("line1", "line2", "line3", "line4")。我们想要打印文件最后4行。当我们读到滴5行时候,数组变成了("line1", "line2", "line3", "line4", "line5")。这时,由于@a在标量环境下估值为5,@a-4值为1。#$a值为4。数组切片@a[@a-4..$#a]则为@a[1..4],这去掉了数组中的第一个元素。当作为替换后@a就变成了("line2", "line3", "line4", "line5")。 ## 89.仅打印匹配模式的行。 perl -ne '/regex/ && print' 此处/regex/是$_ =~ /regex/的缩写。由于-n操作符会把每一行都放到$_变量中,所有匹配模式的行/regex/会返回true,就会打印出行内容。 ## 90.仅打印模式不匹配的行。 perl -ne '!/regex/ && print' 本行和尚一行基本上一样,但是模式表达被取反了。于是会打印所有不匹配的行。 ## 91.打印匹配行之前的一行。 perl -ne '/regex/ && $last && print $last; $last = $_' 本行代码中我们把每一行的内容保存到$last变量中。当行匹配模式的时候,$last中是其上一行的内容,于是打印$last,接着把当前行的内容复赋值给$last变量。 ## 92.打印模式匹配行之后的一行。 perl -ne 'if ($p) { print; $p = 0 } $p++ if /regex/' 此处如果行匹配模式的话我们设置变量$p的值。用它指示下一行将会被打印。当下一行被读到,$p被设置,于是这行被打印,并且$p被又被设置为0,重置其状态。 ## 93.打印任意顺序匹配AAA和BBB的行。 perl -ne '/AAA/ && /BBB/ && print' 本行代码基本上和此前例86一样,只不过这儿测试的模式变成了两个,如果一个行匹配了两个模式,他就会被打印出来。 ## 94.打印不匹配AAA和BBB模式的行。 perl -ne '!/AAA/ && !/BBB/ && print' 本行代码基本上和此前例87一样,此处测试行是否不匹配任意顺序两个模式。如果不匹配/AAA/ 并且不匹配/BBB/,我们打印出这行。 ## 95.打印匹配模式AAA接着模式BBB,再接着模式CCC的行。 perl -ne '/AAA.*BBB.*CCC/ && print' 此处简单的将三个模式AAA,BBB,CCC用“.*”连了起来,表示匹配这所有的或者不匹配。如果AAA跟着BBB又跟着CCC模式,这行就会被打印。他也会匹配AAABBBCCC这样的。 ## 96.打印所有80字符或者大于80字符的行 perl -ne 'print if length >= 80' 本行代码打印所有大于或者等于80字符的行。Perl中你时常可以省略掉函数调用时候的括弧()。此处我们省略了长度函数的括弧。实际上,length,length() 和length($_)都是一样的。 ## 97.打印小于80字符的行。 perl -ne 'print if length < 80' 这和前一行代码相反。检测行长度是否小于80字符。 ## 98.仅带打印13行 perl -ne '$. == 13 && print && exit' 和此前例13介绍的一样,$.变量表示当前行数。所以,如果$.等于13,我们就打印了13行,并退出。 ## 99.打印除27行外的所有行。 perl -ne '$. != 27 && print' 和上一行代码类似,我们检测当前行是否为27行,如果不是我们打印它,否则跳过。 另一种实现同样功能的方式是颠倒print和$.!=27,使用if语句。 perl -ne 'print if $. != 27' ## 100.仅打印13,19和67行。 perl -ne 'print if $. == 13 || $. == 19 || $. == 67' 如果你是用Perl 5.10或者更新版本你可以使用~~~智能匹配符, perl -ne 'print if int($.) ~~ (13, 19, 67)' 智能匹配符“~~”仅在Perl 5.10才推出。你可以用它做所有类型的智能模式匹配。例如,检查是否两个数组是一样的;是否一个数组包含一个元素,以及其他很多用法(见perldoc perlsyn)。在本行代码中我们使用 int($.)~~(13,19,67) 用来检测是否数值$.在列表(13,19,67)中。这基本上是对代码 grep {$_==int($.)} (13,19,67)缩写。如果检测成功,行就会被打印。 ## 101.打印匹配两个模式之间的所有行(包括匹配模式的行) perl -ne 'print if /regex1/../regex2/' 本行代码使用触发操作符,当某行匹配regex1他变为ture,当其后另一行匹配了regex2时候变为false。因此这个行代码就会打印出匹配了两个模式之间的所有行。 ## 102.打印17到30之间所有行 perl -ne 'print if $. >= 17 && $. <= 30' 本行代码非常容易理解。$.变量表示当前行号,于是它检测是否当前行号大于等于17并且小于等于30。 另一种写法是, perl -ne 'print if int($.) ~~ (17..30)' 这行代码使用Perl5.10(或者更新版本)的智能匹配操作符~~。这主要是说,当前行号在列表(17, 18, 19, ..., 30)。如果是,智能模式符匹配成功,行就会被打印。 在老Perl版本你可以用下面的代码代替, perl -ne 'print if grep { $_ == $. } 17..30' 这主要是用grep过程探测,是否当前行号在列表(17, 18, 19, ..., 30)。如果是,返回列表中的一个元素,而有一个元素的列表表示为真,所以行就会被打印。否则的话返回一个空列表,代表为false,就不会得到打印。 ## 103.打印最长的行。 perl -ne '$l = $_ if length($_) > length($l); END { print $l }' 本行代码保存目前看得见最长的行到$l变量中。一旦当前行$_超过了迄今最长的行,就替换它。最后退出之前,在END块执行打印出最长的行$l。 ## 104.打印最短的行。 perl -ne '$s = $_ if $. == 1; $s = $_ if length($_) < length($s); END { print $s }' 本行代码和上一例正好相反。但是我们要找到最短的并且由于$s在首行没有定义,我们必须显式的指定其为第一行,不然后面的小于判断都会失败,得不到想要的结果。 ## 105.打印包含数字的所有行 perl -ne 'print if /\d/' 本行代码使用正则表达式\d,这表示匹配一个数字,检查是否包含,如果包含,检测成功,打印出行。 ## 106.发现仅仅包含一个数字的行。 perl -ne 'print if /^\d+$/' 本行代码和一例相似,不过匹配的不是一行中有个数字,而是锚定行的开始和结束。正则表达式^\d+$表示匹配在行首和行尾之间的一个或者多个数字。 ## 107.打印仅仅包含字母的行。 perl -ne 'print if /^[[:alpha:]]+$/' 本行代码检测是否行中只含有字母,如果是打印出行。此处[[:alpha:]]表示匹配所有的字母。你也可以写为[a-zA-Z]。 ## 108.隔行打印。 perl -ne 'print if $. % 2' 本行代码打印第一,三,五,七等等行。因为$. % 2当当然行号为奇数时候返回真,当前行为偶数时候返回false。 ## 109.从第二行开始隔行打印 perl -ne 'print if $. % 2 == 0' 本行代码和上一例非常相似,但是打印的不是,1,3,5,7,而是2,4,6,8等偶数行。这由于当行号为偶数时候$. % 2 == 0为真。 ## 110.打印所有重复的行。 perl -ne 'print if ++$a{$_} == 2' 本行代码用哈希%a保存了目前为止的所有行,并且计算这些行出现的次数。如果某行出现2次,他就会被打印出,因为此时++$a{$_} == 2为真。如果此行计数多余两次,他不会做任何操作,因为此行已经超过2行,打印检测为false。 ## 111.不重复的打印所有行 perl -ne 'print unless $a{$_}++' 此处,只有行的哈希值$a{$_}为0时候才会打印。每一次Perl读进一行,都会将这个值增加1,所以这使得只有之前都没有出现过的行被打印。