Perl一行式:字段处理和计算
获取每行最后一个字段$ perl -alne 'print $F[$#F]' file.log 这里涉及到了选项"-a"、数组 选项"-a"和awk的自动字段分割一样,会自动将每行数据划分为几个字段。划分字段的分隔符由-F选项指定。如果没有指定-F,则默认以空白符号进行分割(连续空格被认为是单空格)。 分割后的元素全都收集到一个数组 如果想取多个字段,可以对数组 获取范围字段正如上面所解释的,如果想要获取第二个字段到倒数第二个字段: $ perl -lane 'print "@F[[email?protected]]"' 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 如果想要指定空白符号作为字段分隔符,可以考虑其它方式。例如使用 $ 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 这种方式对于大文件肯定是不如前一种方式友好的,因为它会将所有行内容都存储起来,而前一种方式为所有行都只存储一个结果 打乱字段的顺序$ perl -M'List::Util=shuffle' -alne 'print "@{[shuffle @F]}"' file.log 在 $ 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 这里我想介绍的重点是 虽然目的是插入到双引号中,但它的最终目标是为了让数组元素输出时以空格分隔。所以,这种技巧不是唯一的方法,见下一小节。 指定字段输出分隔符上一小节通过 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 特殊变量 例如指定为空格: $ 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 所有行中最小数值假如文件内容为: 1 3 0 9 2 -3 1 10 -2 -3 6 所有行的最小值为-3,如何取得? 最简单的方式是将所有行都读入并保存到数组中,然后使用 $ 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 这里的关键是 首先, $ perl -M'List::Util=min' -anle ' $min = min ($min,@F); END{print $min};' num.log 再者,上面 最后,min函数操作的是一个列表,而Perl会将多个列表压扁形成一个大列表,所以 将所有数值取绝对值假如文件内容为: 1 3 0 9 2 -3 1 10 -2 -3 6 要返回所有数值的绝对值,可以借用默认函数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 其中 统计所有匹配字段数量$ perl -lane '/pattern/ && ++$num for @F;END{print $num || 0}' file.log 这种统计方式是安全的。先划分字段,然后匹配每个字段,只要匹配到就将计数器变量加1。最后输出计数器的值。但可能匹配不到任何东西,所以必须给计数器变量设置一个默认值,也就是 另一种改写方式是: $ perl -anle '$t += /pattern/ for @F;END{print $t}' file.log 这里采用的赋值方式 如果使用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个随机整数。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |