Files
devops/perl/perlonelinecn-master/06有选择的打印或者删除行.md
2025-09-17 16:08:16 +08:00

197 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 有选择的打印或者删除行
## 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'
此处简单的将三个模式AAABBB,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.仅打印1319和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) 用来检测是否数值$.在列表131967这基本上是对代码 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'
本行代码和上一例非常相似但是打印的不是1357而是2468等偶数行这由于当行号为偶数时候$. % 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所以这使得只有之前都没有出现过的行被打印