Perl一行式:字段处理和计算
perl一行式程序系列文章:Perl一行式
获取每行最后一个字段
$ perl -alne 'print $F[$#F]' file.log
这里涉及到了选项"-a"、数组@F
。这里同时还会解释-F选项,它和-a常一起使用。
选项"-a"和awk的自动字段分割一样,会自动将每行数据划分为几个字段。划分字段的分隔符由-F选项指定。如果没有指定-F,则默认以空白符号进行分割(连续空格被认为是单空格)。
分割后的元素全都收集到一个数组@F
中,所以第一个字段的内容是$F[0]
,最后一个字段是$F[-1]
或$F[$#F]
。
如果想取多个字段,可以对数组@F
进行切片,例如第3个字段和第第5个字段@F[2,4]
,第3个字段到倒数第二个字段是@F[2..$#F-1]
或@F[1..~~@F-2]
。
获取范围字段
正如上面所解释的,如果想要获取第二个字段到倒数第二个字段:
$ perl -lane 'print "@F[1..~~@F-2]"' file.log
$ perl -lane 'print "@F[1..$#F-1]"' file.log
指定字段分隔符
之所以单独拿出来解释,是因为"-F"指定分隔符时,空白符号的特殊之处。
对于普通字符,-F自然没有什么问题:
$ perl -F: -alne 'print $F[1]' /etc/passwd
但是想指定空白字符作为字段的分隔符时,"-F"选项将出现故障:
$ perl -F" " -alne 'print $F[1]' file.log
o
a
i
y
y
发现空格分隔符根本没起作用,而是按照NUL作为分隔符对每个字符都分割了。
这个问题在-F选项的官方手册中已经注明了:
You can't use literal whitespace or NUL characters in the pattern
如果想要指定空白符号作为字段分隔符,可以考虑其它方式。例如使用\s
的正则模式,或者直接不使用-F,而是直接在-e表达式中使用split函数进行行的分割。
$ perl -F'\s+' -anle 'print $F[1]' file.log
$ perl -alne 'split / /;print $F[1]' file.log
计算所有行数值的总和
假如文件内容为:
1 3 5 9
2 3 1
10 2 3 6
想要总计所有这些数值之和,可以使用如下方式:
$ perl -M'List::Util=sum' -alne '$num += sum @F;END{print $num}' file.log
或者,将所有行读取到数组中,最后对数组加总:
$ perl -M'List::Util=sum' -alne 'push @S,@F;END{print sum @S}' file.log
这种方式对于大文件肯定是不如前一种方式友好的,因为它会将所有行内容都存储起来,而前一种方式为所有行都只存储一个结果$num
,占用的内存要低的多的多。
打乱字段的顺序
$ perl -M'List::Util=shuffle' -alne 'print "@{[shuffle @F]}"' file.log
在List::Util
模块中有一个函数shuffle,它会按照随机的顺序打乱一个列表(了解即可,这不是本文的重点)。例如:
$ perl -M'List::Util=shuffle' -le 'print "@{[shuffle 1..10]}"'
8 1 3 7 10 5 2 4 6 9
$ perl -M'List::Util=shuffle' -le 'print "@{[shuffle 1..10]}"'
1 2 7 10 8 4 3 5 6 9
$ perl -M'List::Util=shuffle' -le 'print "@{[shuffle 1..10]}"'
2 5 7 1 4 6 3 8 9 10
这里我想介绍的重点是"@{[ shuffle @F ]}"
,它是让一个操作可以插入到双引号中的方法,这个在Perl一行式必知语法基础解释过。
虽然目的是插入到双引号中,但它的最终目标是为了让数组元素输出时以空格分隔。所以,这种技巧不是唯一的方法,见下一小节。
指定字段输出分隔符(无引号包围)
上一小节通过@{[shuffle @F]}
的方式可以将打乱数组的操作插入到双引号中。下面是其它方法。
1.指定数组的字段输出分隔符$,
。
$ perl -M'List::Util=shuffle' -alne 'BEGIN{$,=" "}print shuffle @F' file.log
默认情况下,print/say输出列表的时候,如果数组/列表不插入到双引号中,各元素之间紧连在一起被输出:
$ perl -le '@arr=qw(Shell Perl Python);print @arr'
ShellPerlPython
特殊变量$,
指定的就是print/say输出数组且不插入双引号时的元素分隔符,其默认值为undef。
例如指定为空格:
$ perl -le '
@arr=qw(Shell Perl Python);
$,=" ";
print @arr'
Shell Perl Python
2.将列表join成字符串,join的连接符指定为空格即可。
$ perl -M'List::Util=shuffle' -anle 'print join " ",shuffle @F' file.log
指定字段分隔符(引号包围)
变量$,
控制无双引号包围的数组/列表在print/say输出时的元素分隔符。其实双引号包围的数组/列表被print/say输出时也可以指定元素分隔符。
控制输出双引号包围的列表的元素分隔符的特殊变量是$"
,默认值为空格。
# 默认空格分隔双引号中的元素
$ perl -le '
@arr = qw(Shell Perl PHP Python);
print "@arr"'
Shell Perl PHP Python
# $"改变双引号中的元素分隔符
$ perl -le '
@arr = qw(Shell Perl PHP Python);
$" = ":";
print "@arr"'
Shell:Perl:PHP:Python
所有行中最小数值
假如文件内容为:
1 3 0 9
2 -3 1
10 -2 -3 6
所有行的最小值为-3,如何取得?
最简单的方式是将所有行都读入并保存到数组中,然后使用List::Util
模块的min函数取得。
$ perl -M'List::Util=min' -anle 'push @nums,@F;END{print min @nums}' num.log
但这对于大文件来说内存占用率会很高。比较好的方式是从每行中取出最小值,保留到数组中,最后从这个数组中取出最小值(稍后继续解释更好的方式)。
$ perl -M'List::Util=min' -anle '
push @nums,min @F;
END{print min @nums}' num.log
如果文件的行数量非常大,这也会在内存中保留很多数值,也不是最佳方式。
更好的方式是从每行中取出最小值保存下来,然后和后面的行结合在一起取最小值。这样的方式使得整个处理过程都只占用一行内存空间。
$ perl -M'List::Util=min' -anle '
$min = min ($min // (),@F);
END{print $min};' num.log
这里的关键是min $min//(),@F
。
首先,$min//()
表示如果$num
未定义,则返回空列表()
,否则返回$min
。如果这里不进行$min
是否已定义的判断,那么第一次使用$min
的时候,它被当作空。所以如果文件中没有负数,下面的操作将会因此而返回空。
$ perl -M'List::Util=min' -anle '
$min = min ($min,@F);
END{print $min};' num.log
再者,上面$min//()
在$min
未定义的时候返回的是空列表()
,不能编写为返回0或空,否则就多出了一个要比较的值。
最后,min函数操作的是一个列表,而Perl会将多个列表压扁形成一个大列表,所以$min//(),@F
被压成了一个被min函数操作的列表,而()
表示空列表,这使得第一次使用$min
的时候不会影响要比较的值。
将所有数值取绝对值
假如文件内容为:
1 3 0 9
2 -3 1
10 -2 -3 6
要返回所有数值的绝对值,可以借用默认函数abs来操作。
简单的逻辑可以遍历@F
,并应用abs函数,最后追加回列表被输出:
$ perl -lane '
@line=();
for(@F){push @line,abs};
print "@line";
' num.log
在Perl中,对于列表中每个元素都要检查、操作的情形,可以使用map函数。map函数太强大了,堪称逆天级,map的详细用法参见Perl map用法详解。这里根据此处需求给出map的使用示例:
$ perl -lane 'print "@{[map {abs} @F]}"' num.log
其中map {op} LIST
表示对LIST中的每个元素都执行op操作,操作后的值构成一个新列表。@{[ ]}
的格式在前面已经出现多次了,不再解释。
统计所有匹配字段数量
$ perl -lane '/pattern/ && ++$num for @F;END{print $num || 0}' file.log
这种统计方式是安全的。先划分字段,然后匹配每个字段,只要匹配到就将计数器变量加1。最后输出计数器的值。但可能匹配不到任何东西,所以必须给计数器变量设置一个默认值,也就是$num || 0
。
另一种改写方式是:
$ perl -anle '$t += /pattern/ for @F;END{print $t}' file.log
这里采用的赋值方式$t += /pattern/
,因为/pattern/
返回的是匹配成功的数量,不匹配成功则会返回0,所以无需像前面一样设置计数器变量的默认值。
如果使用grep来改写,则一行式命令如下:
$ perl -alne '$num += grep /pattern/,@F;END{print $num}' file.log
grep返回一个新的表示能匹配的元素列表,但是在标量上下文中列表返回的是元素个数,所以可直接加总计算。
生成10个5-15之间的随机数
$ perl -le 'print "@{[ map int(rand(10)+5),1..10 ]}"'
10 9 9 11 13 10 14 12 13 6
rand(10)表示生成0-9之间的随机浮点数,int(rand(10))表示生成0-9之间的随机整数,加上5表示5-14的随机整数,整个过程执行10次,所以生成了10个随机整数。
生成字母表
$ perl -le 'print a..z'
abcdefghijklmnopqrstuvwxyz
更准确的写法是加上双引号:
$ perl -le 'print "a".."z"'
abcdefghijklmnopqrstuvwxyz
逗号分隔字母表:
$ perl -le 'print join ",","a".."z"'
a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
输出"a"到"zz":
$ perl -le '"a".."zz"'
..
符号会按照字符序列进行递增,"z"递增后得到"aa",再递增得到"ab","az"递增得到"ba",依次类推。所以这里会返回大量字符(共702个字符):
a..z
aa..az
ba..bz
...
xa..xz
ya..yz
za..zz
生成8字符随机密码
$ perl -le 'print map { ("a".."z")[rand 26] } 1..8'
这里("a".."z")[rand 26]
取26个字母中的一个随机字母,1..8
表示生成8个字符。
如果想要包含大小写字母、数字,可以:
$ perl -le 'print map { ("a".."z","A".."Z",0..9)[rand 62] } 1..8'
生成8字符随机密码,包含特殊字符
如果想要让生成的随机密码中包含大小写字母、数字、各种标点符号,可以通过ascii码表来指定范围,然后使用chr函数来转换ascii码为字符。
根据ascii,从33开始到126结束是大小写字母、数字、各种标点符号部分。所以:
$ perl -le 'print map { chr int(rand(94)) + 33 } 1..8'
int(rand(94) + 33)
表示生成33-126(包括126)之间的随机整数,chr函数可以将数值转换为对应的字符。
$ for i in `seq 1 10`;do
perl -le 'print map {chr int(rand(94))+33} 1..8'
done
>t]>W69#
>]e<Hub6
D}R1l)._
*(HKFZ6Q
x++\"=1O
@K)%.N@s
sSji5&FX
o+.#?@/x
^6[l~%-k
.bkTKA[%
Perl一行式:字段处理和计算的更多相关文章
- Perl一行式:处理行号和单词数
perl一行式程序系列文章:Perl一行式 所有行的行号 $ perl -pe '$_ = "$. $_"' file.log $ perl -ne 'print "$. ...
- Perl一行式:选择行输出、删除、追加、插入
perl一行式程序系列文章:Perl一行式 对于Perl的一行式perl程序来说,选择要输出的.要删除的.要插入/追加的行是非常容易的事情,因为print/say决定行是否输出/插入/追加/删除.虽然 ...
- Perl一行式:文本编解码、替换
perl一行式程序系列文章:Perl一行式 文本大小写转换 全部字符转换成大写或小写,有几种方式: # 转大写 $ perl -nle 'print uc' file.log $ perl -ple ...
- Perl一行式:处理空白符号
perl一行式程序系列文章:Perl一行式 假如文件file.log内容如下: root x 0 0 root /root /bin/bash daemon x 1 1 daemon /usr/sbi ...
- python中class 的一行式构造器
好处:避免类初始化时大量重复的赋值语句 用到了魔法__dict__ # 一行式构造器 class Test(): # 初始化 def __init__(self, a, b, c=2, d=3, e= ...
- 通过sql的stuff 把一列几行的记录拼接在一行一个字段
---通过sql的stuff 把一列几行的记录拼接在一行一个字段 select FID,a.FCustomerID as 工地ID , 应验收节点 = (stuff((select ',' + isn ...
- Python一行式代码
# 简易Web Server,可以直接快速共享文件 python -m http.server # 脚本性能分析 python -m cProfile my_script.py # 列表辗平 impo ...
- Oracle修改字段长度以及计算天数
sql修改字段长度的语法: alter table 表名 modify 字段名 字段类型; sql修改字段长度的示例代码 alter table qtline modify qtl_bidernote ...
- Redis基于eval的多字段原子增量计算
目录 目录 1 1. 前言 1 2. 优点 1 3. 方法一:使用struct 2 3.1. 设置初始值(覆盖原有的,如果存在) 2 3.2. 查询k1的值 2 3.3. 设置初始值(覆盖原有的,如果 ...
随机推荐
- jquery,html5,css3主要特性总结
jquery特性: 1.丰富简单的DOM选择器 2.同一函数实现get和set 3.支持链式方法书写 4.完善的事件处理功能 5.强大的css动画效果 6.完善的Ajax 7.简单的元素样式操作 8. ...
- Linux编程之fork函数
在Linux中,fork函数的功能就是在一个进程中创建一个新的进程,当前调用fork函数的进程就是产生的新进程的父进程,新进程在以下也称为子进程.在新进程生成之后就会在系统中开始执行. 函数原型:pi ...
- ppt制作动态表格与文字
在工作中经常与ppt打交道的小伙伴们,是不是非常想让自己做的ppt图表能够动起来,显得高大上一点呢?比如让柱形图慢慢长起来,让折线图慢慢画出来,让文字像字幕一样缓缓上升?本文将给大家整理几 ...
- Docker构建其它组件
构建mysql 运行centos7容器 docker run --privileged -dti --name=centos-container centos:7 /usr/sbin/init 查询c ...
- jquery1.6中的.prop()和.attr()异同
jquery jQueryHTML5JavaScript浏览器ITeye 最近在iteye的新闻中看到jQuery已经更新到了1.6.1.和之前版本的最大变化是增加了.prop方法.但是.prop( ...
- lua-01
ctrl + shift + L 多行编辑 ctrl + D 继续向下选中下一个相同的文本 Alt + F3 选中所有相同所选中德文本 =>Lua的快捷键 回调代码: function fact ...
- shiro认证流程
创建测试工程 加入shiro-core的jar包及其依赖包 与其它java开源框架类似,将shiro的jar包加入项目就可以使用shiro提供的功能了.shiro-core是核心包必须选用,还提供了与 ...
- genymotion常见问题解答
[转]常见问题解答 很多人喜欢使用Genymotion这款安卓模拟器,但是虽然Genymotion很好用,可是却有各种问题存在哦,下面潇潇就一些常见的Genymotion问题来说下解决方法吧. 为什么 ...
- Scala - 快速学习03 - 基础语法
1- 变量 变量 mutable variable 在程序运行过程中其值可能发生改变的量 关键词var定义变量,定义时直接进行求值 常量 immutable variable 在程序运行过程中其值不会 ...
- 【design patterns】设计模式
1.单例设计模式(singleton) 用途举例:对于多个程序使用同一个配置信息对象时比如在连接数据库时使用单例模式,每次只取出一个连接 步骤:①私有化该类的构造函数 ②私有化一个静态的对象 ③公有化 ...