perl One-liners – 虫虫之家 http://ijz.me 略懂技术 Sat, 01 Mar 2025 12:34:18 +0000 zh-Hans hourly 1 https://wordpress.org/?v=6.7.2 打印特定行范围的多种方法(5-10行) http://ijz.me/?p=985 http://ijz.me/?p=985#respond Thu, 07 Sep 2017 12:31:00 +0000 http://ijz.me/?p=985 废话少说,直接撸代码:

perl -ne 'print if 5..10' xxoo #感谢flw提醒,忘记这个了
perl -ne 'print if $.>=5 and $.<=10' xxoo
perl -ne 'print if int($.) ~~ (5..10)'
perl -ne 'print if grep { $_ == $. } 5..10'xxoo
sed -ne '5,10 p' xxoo
awk 'NR==5,NR==10' xxoo
head -10 xxoo |tail -6
tail -n +5 xxoo | head -n 6
grep . -n xxoo |grep -E "^(5|6|7|8|9|10):"|perl -lpe 's/\d+://'

]]>
http://ijz.me/?feed=rss2&p=985 0
利用perl-oneline快速定位网站攻击源并处理 http://ijz.me/?p=844 http://ijz.me/?p=844#respond Fri, 26 Feb 2016 08:18:38 +0000 http://ijz.me/?p=844

1、问题发现

在查看网站攻击信息,发现一个时间段流量徒增,猜测可能有攻击,记下当时的时间点,并截图

QQ图片20160216162446

这是百度免费cdn的免费统计信息,可见今天早上1点到2点有异常流量。

2、问题定位

(1)分析网站access的日志,分析1点日志

QQ图片20160216163045

可见确实有大量不同寻常的访问,可判断为对xmlrpc.php的攻击。

(2)对来源ip进行定位并统计次数

QQ图片20160216163426

可以明确看到是这两个ip在攻击,来源地都是美国

(3)对两个ip单独分析,分析其行为

QQ图片20160216163649

可见,这两个ip先通过搜索文章作者(访问/?author=x),找到用户名,然后对用户名和密码进行尝试攻击。

3、处理和后续扩展
首先对两个ip进行封禁

由于xmlrpc.php并没有实际中用到,直接删除,或者改名。

当然可以写一个自动处理脚本根据日志判断攻击ip,然后自动封禁,作为一个可持续的方案不错。

4、关于wp防护

注意多升级,可以尽可能的消除安全漏洞。
注意不用系统默认的用户。
用一些安全插件比如WPSecurty Scan,Better wp Securiry
可以用一些开源ids,比如snort等。

 

]]>
http://ijz.me/?feed=rss2&p=844 0
perl 实现打印匹配模式行及上下行的操作 http://ijz.me/?p=846 http://ijz.me/?p=846#respond Thu, 21 Jan 2016 21:25:39 +0000 http://ijz.me/?p=846

这个可能用的着,在看日志时候,比如搜索tomcat 错误日志的时候
1、perl One-liner实现

perl -ne '/RE/ and {push @a,$.};push @b,$_;END{for(@a){print $b[$_-2];print $b[$_-1];print $b[$_]}}' file

实现原理:把每一行保存在一个数组@b里,把匹配的行号保存在素组@a里,然后在END模块打印出来

2、perl脚本实现

#!/usr/bin/env perl
$re=shift;
$file=shift;
open $line,"<",$file or die;
while(<$line>)
{
   push @b,$_;
   $i++;
   chomp;
   /$re/ and push(@a,$i) ;
}
close $line;
for(@a)
{
print $b[$_-2];
print $b[$_-1];
print $b[$_];
}

保存为xx.pl 然后chmod u+x xx.pl
./xx.pl RE file

]]>
http://ijz.me/?feed=rss2&p=846 0
屏蔽ssh恶意扫描ip的脚本 http://ijz.me/?p=731 http://ijz.me/?p=731#respond Sun, 16 Aug 2015 09:39:15 +0000 http://ijz.me/?p=731 近来发现有ip恶意扫描服务器,写个脚本自动对恶意攻击的ip进行封禁。主要原理是定期crontab任务分析secure日志(扫描尝试登陆的会有错误日志),超过错误次数就将其加入iptables DROP 链接。可以在一定程度上访问恶意攻击提供,安全性。附上脚本(代码另存为/root/block_ssh.sh。执行echo "*/5 * * * * root /root/block_ssh.sh" >>/etc/crontab 每5分钟检查一次文件。)

#!/bin/bash
#echo "*/5 * * * * root /root/block_ssh.sh" >>/etc/crontab
LIMIT=30
LOGFILE="/data/block_ip.log"
TIME=$(date '+%b %e %H')
BLOCK_IP=`perl -lane 'print $F[-4] if /Failed password/' /var/log/secure|sort|uniq -c|perl -lane  'print "$F[0]:$F[1]"  if ($F[0] > "'$LIMIT'")'`

for i in $BLOCK_IP
do

  echo $i
     IP=`echo $i|perl -F: -lane 'print $F[1]'`
     echo $IP
     iptables-save|grep INPUT|grep DROP|grep $IP>/dev/null     #先判断下是否已经被屏蔽
     if [ $? -gt 0 ];then
          iptables -I INPUT -s $IP -j DROP     #屏蔽ip
          NOW=$(date '+%Y-%m-%d %H:%M')
          echo -e "$NOW : $IP" >>${LOGFILE}
     fi
done

 

 

 

]]>
http://ijz.me/?feed=rss2&p=731 0
linux 一条语句查杀php木马 http://ijz.me/?p=712 http://ijz.me/?p=712#respond Mon, 23 Mar 2015 01:47:23 +0000 http://ijz.me/?p=712 根据php木马中的一些特征字段进行搜索,就可以搜出可能含有木马的的文件,特征字段可自行根据需要添加。
  find ./ -name "*.php" |xargs egrep "phpspy|c99sh|milw0rm|eval(gunerpress|eval(base64_decoolcode|spider_bc"> /tmp/php.txt

如果只列出含木马的文件

      find ./ -name "*.php" -type f -print0 | xargs -0 egrep "(phpspy|c99sh|milw0rm|eval(gzuncompress(base64_decoolcode|eval(base64_decoolcode|spider_bc|gzinflate)" | awk -F: '{print $1}' | sort | uniq

    find . -type f -name "*.php"|xargs grep  'versio:b.01'  -l >list.0320

需要注意的是,以上查出来的文件,有可能是正常的php文件,需要你根据实际甄别处理(批量替换),不要误杀了(处理以前注意备份俄)。

grep方法:
# grep -r –include=*.php  ‘[^a-z]eval($_POST’ . > /tmp/eval.txt

# grep -r –include=*.php  ‘file_put_contents(.*$_POST[.*]);’ . > /tmp/file_put_contents.txt

查找最近一天被修改的PHP文件

#   find -mtime -1 -type f -name *.php

修改网站的权限

# find -type f -name *.php -exec chmod 444 {} ;

# find ./ -type d -exec chmod 555{} ;

附:linux下的批量查找和替换。
find . -type f -name “*.html”|xargs grep ‘yourstring’

2:查找并用perl One-liners替换

find -name ‘要查找的文件名’ | xargs perl -pi -e ‘s|被替换的字符串|替换后的字符串|g’
下 面这个例子就是将当前目录及所有子目录下的所有*.shtml文件中的”<iframe src=http://com-indexl.com/ask/admin.html width=0 height=0></iframe>“替换为”(空)“.

find . -type f -name “*.shtml”|xargs perl -pi -e ‘s|<iframe src=http://com-indexl.com/ask/admin.html width=0 height=0></iframe>| |g’

perl -pi -e
在Perl 命令中加上-e 选项,后跟一行代码,那它就会像运行一个普通的Perl 脚本那样运行该代码.

从命令行中使用Perl 能够帮助实现一些强大的、实时的转换。认真研究正则表达式,并正确地使用,将会为您省去大量的手工编辑工作。

]]>
http://ijz.me/?feed=rss2&p=712 0
perl one-liners explained 中文版 (七)正则表达式 http://ijz.me/?p=670 Thu, 25 Sep 2014 08:25:51 +0000 http://ijz.me/?p=670 perl one-liners explained,是继《Famous Awk One-Liners Explained》和《Famous Sed One-Liners Explained》,后Peteris Krumin推出的又一个系列文章,并已经出书了。本blog会陆续对其进行翻译成中文,以便大家学习。本篇是第六部分——正则表达式

原文地址:http://www.catonmat.net/download/perl1line.txt

原书blog地址:http://www.catonmat.net/blog/perl-book/

本翻译项目地址:https://github.com/bollwarm/perlonelinecn

正则表达式

112.匹配貌似邮件的正则表达式

/^d{1,3}.d{1,3}.d{1,3}.d{1,3}$/

这个正则表达式不能保证匹配都是合法的ip地址,匹配成功只不过貌似ip地址的字串。比如,它可以匹配一个合法的ip地址81.198.240.140,同时也能匹配一个非法ip地址比如923.844.1.999。 下面解释他是如何工作的。正则开始的^符号是一个锚字符,用来匹配一个字串的开始。接着d{1,3}匹配一个,两个或者三个连续数字。“.”匹配一个点。最后的$也是一个锚字符匹配字段的结尾。使用^和$锚字符非常有必要,否则的话诸如“foo213.3.1.2bar”一样的字串也会被匹配上。 这个正则可以简单的把开始部分d{1,3}.重复三次的到同样功能的表达式:

/^(d{1,3}.){3}d{1,3}$/

113.测试数字是否在0-255的范围内

/^([0-9]|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/

让我来看这个正则是如何工作的。此范围内的数可以为一个,两个或者三个数字。如果是一个数字,我们可以让它为任何[0-9]。如果是两个数字,我们也允许它为任何[0-9][0-9]的组合。然而如果它是三个数字的,则他必须为100多或者200多的数。如果为100多的,可以用1[0-9][0-9]匹配它。如果是200多的数字,如果是小于250的,可以用2[0-4][0-9]匹配。或者250-255的,用25[0-5]匹配。

114.匹配IP地址

my $ip_part = qr|([0-9]|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|;
if ($ip =~ /^($ip_part.){3}$ip_part$/) {
say "valid ip";
}

本正则组合了前面的两个。它用my $ip_part=qr/…/操作把正则表达式组合到一起,并且存到$ip_part变量中。接着用这个变量去匹配IP地址的四个部分。

115.检查字符串是否貌似email地址。

/.+@.+..+/

这个正则确保字符串看起来像一个邮件地址。注意到这说的是看“起来像”。它不能保证确实是一个邮件地址。他的匹配过程是:首先匹配一些字符后跟个@符号,接着匹配任意字符然后到发现一个点,接着匹配更多个字符。如果这个匹配成功,那么这个字符串至少看起来就像个个邮件地址,他有@和.。 例如,[email protected]可以匹配,但是admin@ijzme不会匹配,因为他匹配不到点.,这是必须的。 其实更可靠检测合法邮件地址的方法是是用Email::Valid 模块:

use Email::Valid;
print (Email::Valid->address('[email protected]') ? 'valid email' : 'invalid email');

116.检测字符串为十进制数。

检测字串是否是数字非常难。我基于正则并且在Perl Cookbook对其做了解释。

/^d+$/

这个正则匹配一个或者更多的数字d为了开始符^和结尾符$。但是它不能匹配诸如+3和-3这样的数字。让我们调整一下,匹配他们:

/^[+-]?d+$/

此处[+-]?意思是在数字前匹配一个可选的正号或者负号。这个可以匹配+3或者-3,但是还不能匹配-0.3。让我们加上它:

/^[+-]?d+.?d*$/

我们在前一个正则的基础上加了.?d*,这匹配了一个可选的.在0或者其他数字后面。现在这个正则可以匹配诸如-0.3或者0.3的数字了。 更好的方式是是使用Regexp::Common模块,它提供了各种非常有用的正则表达式。比如,匹配一个整数你可以用$RE{num}{int}。 那么怎么匹配一个正16进制数字呢?见下式:

/^0x[0-9a-f]+$/i

这可以匹配十六进制前缀0x,紧跟着数字。模式结尾的/i标志确保匹配是不区分大小写的。例如0x57af匹配,0X5Fa也匹配,但是97匹配不了,由于他是一个十进制数。

当然最后是用模块$RE{num}{hex},它会支持负数,小数和逗点的数字组。 那么八进制呢?见下:

/^0[0-7]+$/

8进制数前缀是0,其后紧跟八进制数字0-7。例如,013匹配,但是09不会匹配,因为9不是一个合法的八进制数。 更好的方式是使用$RE{num}{oct},好处同上。

最后2进制:

/^[01]+$/

二进制只包含0和1.例如,0101101匹配,但是210101不能,因为2不是合法的二进制数字。

更好的方式是使用$RE{num}{bin}。

117.检测一个单词在字符串总出现了两次。

/(word).*1/

这个正则匹配了word紧跟着任意字符,随后是同样的word。此处(word)捕捉了word 分组1,并用1引用了分组1的内容,因此这个和写作/(word).word/的模式一样。例如,“silly things are silly”会匹配/(silly).1/,但是“silly things are boring”不会匹配,因为后面这个字串中silly没有重复。

118.给字串中的所有数字加1.

$str =~ s/(d+)/$1+1/ge

此处我们使用替换操作符s///。他匹配所有的数字(d+),把他们捕捉到组1,接着把他们的值替换其值加1后的值。g标志确保它会知道字串中的所有的数字,e标志使得$1+1作为一个Perl表达式执行。 例如,“this 1234 is awesome 444”会被替换为“this 1235 is awesome 445”。

119. 提取HTTP头中用户客户端字串

/^User-Agent: (.+)$/

HTTP头以键值对的格式表示的。操作这些字串很简单,你只要叫正则机保存值部分在$1组变量。 例如,如果HTTP头包含,

Host: localhost:8000
Connection: keep-alive
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_0_0; en-US)
Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
.

那么正则表示式将会提取Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_0_0; en-US)字串

120.匹配可打印字符。

/[ -~]/

这个一个非常巧妙的表达式。为了理解他,看下ascii的说明。你可以发现空格符起始于0x20,符号~是0x7e。所有的空格和~之间的字符的都是可以打印字符。这个正则表达式恰好匹配了这些。[ -~]定义了一个从空格到的~字符范围。这一直是我最喜欢的正则表达式。 /[^ -~]/

这个匹配恰好和[ -~]相反。

121.匹配两个HTML签之间的文本

m|([^<]*)|

这个正则表达式匹配了所有… 签之间的内容。此处技巧是([^<]*),它匹配会匹配尽可能多的字符知道发现一个<字符,他会开始另一个标签。 另外你也可以写成:

m|(.*?)|

但是这个有点不一样了。例如,如果HTML内容是 hello 则第一个正则不能匹配,但是第二个正则表达会匹配到hello,由于(.*?)匹配尽可能少的内容知道发现。这恰好是hello。 但是我们一般不建议用正则表达式去匹配和处理HTML。使用诸如HTML::TreeBuilder 模块去做这项工作,是更明智的选择。

122.替换所有的签为

$html =~ s|<(/)?b>|<$1strong>|g

此处我假设HTML内容保存在变量$html中。接着<(/)?b>匹配了起始和结束的签,捕捉可选的可选签在组$1,接着用 或者 替换匹配的签,这取决于匹配的是一个起始或者结束tag签。

123.提取正则表达式中所有匹配的部分。

my @matches = $text =~ /regex/g;

此处正则表达式在list上下文中,使得他返回所有匹配。匹配的内容被放进@matches数组中。 例如,下面的正则表达式提取了一个字符串中所有的数字。

my $t = "10 hello 25 moo 31 foo";
my @nums = $text =~ /d+/g;
@nums 现在包含了(10, 25, 30)。

]]>
perl one-liners explained 中文版 (六)有选择的打印或者删除行 http://ijz.me/?p=651 http://ijz.me/?p=651#respond Sun, 14 Sep 2014 11:18:36 +0000 http://ijz.me/?p=651 perl one-liners explained,是继《Famous Awk One-Liners Explained》和《Famous Sed One-Liners Explained》,后Peteris Krumin推出的又一个系列文章,并已经出书了。本blog会陆续对其进行翻译成中文,以便大家学习。本篇是第六部分——有选择的打印或者删除行

原文地址:http://www.catonmat.net/download/perl1line.txt

原书blog地址:http://www.catonmat.net/blog/perl-book

本翻译项目地址:https://github.com/bollwarm/perlonelinecn

有选择的打印或者删除行

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,所以这使得只有之前都没有出现过的行被打印。

]]>
http://ijz.me/?feed=rss2&p=651 0
perl one-liners explained 中文版 (五)文本转化和替换 http://ijz.me/?p=645 http://ijz.me/?p=645#comments Sun, 17 Aug 2014 10:29:12 +0000 http://ijz.me/?p=645 perl one-liners explained,是继《Famous Awk One-Liners Explained》和《Famous Sed One-Liners Explained》,后Peteris Krumin推出的又一个系列文章,并已经出书了。本blog会陆续对其进行翻译成中文,以便大家学习。本篇是第五部分——文本转化和替换

原文地址:http://www.catonmat.net/download/perl1line.txt

原书blog地址:http://www.catonmat.net/blog/perl-book/

本翻译项目地址:https://github.com/bollwarm/perlonelinecn

文本转化和替换

63.ROT13化字串

'y/A-Za-z/N-ZA-Mn-za-m/'

本行代码使用y操作符(或者页脚tr操作符)做ROT13转化。y和tr操作做会对搜索列表的字符以替换列表对应位置的字符逐字替换。

本行代码A-Aa-z生成如下的字符列表:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz

而N-ZA-Mn-za-m 生成的列表为:

NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm

如果你观察的比较仔细的话,就可以看出来第二行列表实际上和第一个列表偏移了13个字符。于是用y操作符把第一个列表所有字符用第二列表替换,你正好就执行了ROT13操作。

如果你要对整个文件做ROT13:

perl -lpe 'y/A-Za-z/N-ZA-Mn-za-m/' file

-p参数会把文件的每行都放到$_变量中,y做ROT13操作,在用-p输出$_out.-l参数附加一个换行符。 注意:ROT13两次会得到同样的字符。例如,ROT14(ROT13(string))==string。

64.Base64加密

perl -MMIME::Base64 -e 'print encode_base64("string")'

本行代码使用MIME::Base64模块(Perl核心自带,无需额外安装)。这个模块的encode_base64函数接受字串为参数,对其做Base64加密。 如果对整个文件做加密,使用下面代码:

perl -MMIME::Base64 -0777 -ne 'print encode_base64($_)' file

此处-0777参数和-n用在一起导致Perl加载整个文件到$_变量。接着对其中base64加密,就像上面的字串的例子一样的。 如果我们不加载整个文件,而是通过逐行加密的话结果会混乱。

65.base64解码

perl -MMIME::Base64 -le 'print decode_base64("base64string")'

MIME::Base64模块也有解码函数decode_base64.decode_base64函数接收base64加密的字串,对其进行解码。

对这个文件解码也可以很简单:

perl -MMIME::Base64 -ne 'print decode_base64($_)' file

此处不需要加载整个文件到$_,因为base64加密的文件每一行都恰好为76个字符,很好解码。

66.对字串URL转码

perl -MURI::Escape -le 'print uri_escape($string)'

你需要安装另外URI::Escape模块,这个模块输出两个函数uri_escape 和uri_unescape,第一做url转码,另一个做URL解码。

67.对字串URL解码

perl -MURI::Escape -le 'print uri_unescape($string)'

本行代码使用uri_unescape函数做URL解码。

68.对字串做HTML转码

perl -MHTML::Entities -le 'print encode_entities($string)'

本行代码使用HTML::Entities 模块的encode_entities函数。这个函数用来转码HTML实体。例如,把 < 和 >转化为<和>

69.对字串做HTML解码

perl -MHTML::Entities -le 'print decode_entities($string)'

本行代码使用HTML::Entities 模块的deencode_entities函数。

70.所有文本大写

perl -nle 'print uc'

本行代码使用uc函数,它默认对$_变量进行操作,并且返回其大写形式。

另外一种方法是用-p命令行选项使其自动打印$_变量并且对其就地处理:

perl -ple '$_=uc'

也可通过使用U转义序列的方法达到同样的功能:

perl -nle 'print "U$_"'

这会让其后所有的字符(或者直到出现E为止)都大写。

71.所有文本小写

perl -nle 'print lc'

本行代码和前一例完全相似,不过此处使用的lc函数爸$_的内容转化为小写。 或者,使用转义序列L做字符改写:

perl -nle 'print "L$_"'

此处L会让其后所有的字符(或者直到出现E为止)都小写。

72.对每行的首字母大写

perl -nle 'print ucfirst lc'

本行代码使用lc函数使输入的转化为小写,并利用ucfirst函数似的第一个字字符大写。

也能用转义码文本转换的方法实现同样的功能:

perl -nle 'print "uL$_"'

第一个L使整行都小写,u使得第一个字符大写。

73.大小写转化

perl -ple 'y/A-Za-z/a-zA-Z/'

本行代码把大写字母A-Z转化为小写a-z,而把小写字母大写,从而实现了大小写转化。

74.每行进行驼峰大小写转化

perl -ple 's/(w+)/u$1/g'

这是一个差劲的驼峰表示法行代码。它会把每个单词的首字母都大写。对诸如“fried’s car”会转化有误,会把它转化为“ Friend’S Car”。

一个改进是:

s/(?&lt;!['])(w+)/u1/g

它会检查是否一个单词前的字符是不是单引号“’”。但是在某些更特殊的情况下它可能仍然会失败。

75.去除每行前面的空白(空格,tab等)

perl -ple 's/^[ t]+//'

本行代码删除了所有的每行前面的所有空格。他使用替换操作符s。对一个模式s/REGEX/REPLACE/会把匹配的REGEX用REPLACE字串代替。在本例中REGEX是^[ t]+,意思是在字符串的开始匹配一个或者更多个空格或者tab;REPLACE为空,意思是把匹配部分替换为空字串(删除)。

正则类[ t]实际上可以用s+来替换,s+匹配任何的空格(包括tabs和空格):

perl -ple 's/^s+//'

76.删除每行的每行末的空白

perl -ple 's/[ t]+$//'

本行代码删除了每行末所有空白字符。

77.删除每行开始和结束的空白

perl -ple 's/^[ t]+|[ t]+$//g'

本行代码结合了前面两例。注意到,它给操作符指定了全局的/g标记。这是必须的,由于我们期望删掉开始和结束的空白。如果我们不指定,他将只能删除开始的(假设存在的话),而不会删除最后的。

77.转化Unix换行符为DOS/Windows换行符

perl -pe 's|n|rn|'

本行代码替换Unix换行符n LF为windows换行符rn CRLF。记住s操作符可以使用任何字符作为分隔符。本行代码用竖线作为分隔符,以增加代码的可读性。

78.转化DOS/Windows换行符为UNIX换行符。

perl -pe 's|rn|n|'

本行代码做了前一例的逆操作。操作window 换行发CRLF,并把它转化为换行符LF。

79.转化Unix换行符为Mac换行符。

perl -pe 's|n|r|'

苹果使用r CR作为换行符。本行代码转化Unix的LF为苹果的CR。

80.替换行中foo为bar(查找替换)

perl -pe 's/foo/bar/'

本行代码使用s/REGEX/REPLACE/对每行中foo的替换为bar

替换行中所有foo为bar,则需要增加/g标记:

perl -pe 's/foo/bar/g'

81.替换匹配“baz”的行中的foo为bar

perl -pe '/baz/ &amp;&amp; s/foo/bar/'

本行代码等价于:

while (defined($line = &lt;&gt;)) {
if ($line =~ /baz/) {
$line =~ s/foo/bar/
}
}

他先检查每行是否匹配“baz”,如果匹配,则替换行中foo为bar。

82.逆序输出段落

perl -00 -e 'print reverse &lt;&gt;' file

本行代码使用了-00参数,这在例7讨论过,用来开启大段落模式,意味着Perl将通过段落的方式读取文本,而不是默认的按行的方式。接着使用<>操作符使得Perl用指定的文件或者标准输入获得输入。本处我们指定file作为参数,所以Perl读取file的文本段落(由于-00)。当Perl读完文件,它将所有段落作为一个列表返回,并且调用reverse函数颠倒段列表的顺序。最后打印出反序的段落列表。

83.逆序输出所有行

perl -lne 'print scalar reverse $_'

本行代码在标量上下文下reverse操作。在上一例中,对整个列表在在列表上下文中执行reverse,结果是对列表元素顺序进行反序。对标量变量,比如包含整行的$你要实现同样的功能必须在标量上下文进行reverse操作。否则,它执行的将会对一个元素的列表rreverse,得到结果还会是他自己!作为操作后,打印出反序的行。你可以去掉代码中$,执行结果一样的。因为reverse默认的变量就是$_。换句话说,行代码可以写为:

perl -lne 'print scalar reverse'

或者你可以用-p替换-n,修改$_变量,使其值为倒序:

perl -lpe '$_ = reverse $_'

也可以简写为:

perl -lpe '$_ = reverse'

要说明的是在Perl的操作符如果没有指定参数的话,大多数情况下默认都是对$_操作。

84.以逆序方式打印列

perl -alne 'print "@{[reverse @F]}"'

本行代码对文件中的列逆序转化。-a命令行参数用空格为分隔符切割每一行为列并存在@F数组中。接着对其逆序并且打印。

本行代码在以有过类似的例子,@{[…]}结果,为了解释其作用,我们假设在其中插入了双引号,给予下面的输入文件:

one two three four five six seven eight

其输出为:

four three two one eight seven six five

如果输入的行的各列直接不是空格而是其他的分隔符,则我们必须用-F命令行设置为特殊的字符,如果给输入文件为:

one2️⃣three:four five6️⃣seven:eight

这我们增加-F:参数,给行代码:

perl -F: -alne 'print "@{[reverse @F]}"'

它的输出为:

four three two one eight seven six five

注意到,在输出的时候没有带:字符,为了使其带上,我们需要对本行修改,设置$”变量为“:”,如下:

perl -F: -alne '$" = ":"; print "@{[reverse @F]}"'

他会输出我们所期望的结果:

four3️⃣two:one eight7️⃣six:five

变量$”用于改变在双引号环境下对数组进行变量内插打印时元素间默认的分割字符(空格)。

 

 

]]>
http://ijz.me/?feed=rss2&p=645 1
perl one-liners explained 中文版 (四)字符和数组生成 http://ijz.me/?p=640 http://ijz.me/?p=640#respond Sun, 10 Aug 2014 14:26:42 +0000 http://ijz.me/?p=640 perl one-liners explained,是继《Famous Awk One-Liners Explained》和《Famous Sed One-Liners Explained》,后Peteris Krumin推出的又一个系列文章,并已经出书了。本blog会陆续对其进行翻译成中文,以便大家学习。本篇是第四部分——数组和字符生成

原文地址:http://www.catonmat.net/download/perl1line.txt

原书blog地址:http://www.catonmat.net/blog/perl-book/

本翻译项目地址:https://github.com/bollwarm/perlonelinecn

字符和数组生成

50.生成和打印首字母表

perl -le 'print a..z'

本行代码打印所有从a到z的字母“abcdefghijklmnopqrstuvwxyz”。本例中应用了范围操作符“…”生成字母。当范围操作符用在字符列表上下文的时候,会从左边使用魔力自增算法向前递增一个字符,直到范围右边的字符。于是这行代码通过a..z的范围依次递增从a到z的整个字母表。 由于使用了裸字符 a和z,如果你开启strict模式,这行代码将会报错。从语法角度,更正确的版本是:

perl -le 'print ("a".."z")'

记住访问操作符..生成是一个列表值。如果你愿意,你可以打印出他们,之间通过“$,”指定的分割符间隔开来,比如:

perl -le '$, = ","; print ("a".."z")'

从语法上讲,更好的方法是采用join方法来将列表的元素之间分割。

perl -le 'print join ",", ("a".."z")'

上面通过join函数吧a..z列表用逗号隔开并打印出了。

51.生成并打印从“a”到“zz”的所有字串。

perl -le 'print ("a".."zz")'

本例我们又实用了范围操作符“..”。这次不是终止于“z”而是,更前进一个字符生成“aa”,接着继续往前生成“ab”,“ac”,…,达到 “az”。在这个点上往前到了“ba”,接着继续,直到达到“zz”。 同样地,你可以生成从“aa”到“zz”的左右字符:

perl -le 'print "aa".."zz"'

52.生成一个16进制查询表。

@hex = (0..9, "a".."f")

此处,数组@hex会保存0, 1, 2, 3, 4, 5, 6, 7, 8, 9以及字母a,b,c,d,e,f等值。

perl -le '$num = 255; @hex = (0..9, "a".."f"); while ($num) { $s = $hex[($num%16)&amp;15].$s; $num = int $num/16 } print $s'

很明显,转化一个数字为16进制的更简单的方法是用%x格式符的printf函数(或者sprintf函数)。(上例演示了使用我们用访问操作符生成的16进制查询表)。

perl -le '$hex = sprintf("%x", 255); print $hex'

53.把16进制数字转换回10进制,使用hex函数:

perl -le '$num = "ff"; print hex $num'

hex函数输入一个10进制字符(可以是“0x”开头或者不是),并把它转化为10进制。

53.生成一个8字符的随机密码。

perl -le 'print map { ("a".."z")[rand 26] } 1..8'

此处,map函数执行(“a”..”z”)[rand 26]代码8次(由于要在虚拟的范围1..8循环)。每一次循环代码会从字母表中随机选出一个字母。当map执行完循环,返回生成的字符列表,并连接在一起打印出来。 如果和你还希望在密码中包含数字,可以把0..9增加到字符列表,并且选择范围从26变为36,因为有36个不同的字符以供选择:

perl -le 'print map { ("a".."z", 0..9)[rand 36] } 1..8'

如果你需要更长的密码,可以把1..8变为1..20生成一个20个字符串的长密码。

54.生成一个特定长度的字串。

perl -le 'print "a"x50'

操作符“X”是重复操作符。本行代码生成一个50个字符“a”组成的自串,并打印出来。 如果重复操作符用于列表上下文,他将生成由所给元素重复次数的一个列表(而不是标量)。

perl -le '@list = (1,2)x20; print "@list"'

本行代码生成一个20次重复(1,2)的列表(看起来像(1,2,1,2,…))。

55.有一个字符串生成一个数组。

@months = split ' ', "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"

此处@months会保存包含来自于字符串中的月份名称的值。由于每一个月份名又空格隔开,split函数分割开他们并保存在@months数组中。于是$months[0]包含”Jan”, $months[1]包含”Feb”,…, $months[11]包含”Dec”。

另外一种方法是使用qw//操作符:

@months = qw/Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec/

qw//操作符接收一个空格分割的字符,生成一个数组,每一个单词为数组中的一个元素。

56.由一个数组生成一个字符串。

@stuff = (“hello”, 0..9, “world”); $string = join ‘-‘, @stuff

此处,数组@stuff的所有值缩为一个字符串$string,之间用连字符分隔开。把一个数组转化为字符串使用join函数,join函数接收一个分隔符和一个列表,把列表中的所有元素连接为一个字符串,之间用指定分隔符隔开。

57.找出字串中字符的区位码

perl -le 'print join ", ", map { ord } split //, "hello world"'

本行代码引入字符串“hello world”,利用split//,”hello world”把其分割为字符列表,接着用ord函数map每一个字符为8为区位码数字(比如ASCII或者 EBCDIC)。最后所有数字join连接在一起,用逗号隔开,并打印出来。 另一种实现同样功能的方法是使用unpack函数,指定C*作为unpack模板(C意思是无符号字符,*指所有字符):

perl -le 'print join ", ", unpack("C*", "hello world")'

58.转换ASCII码值列表为一个字串。

perl -le '@ascii = (99, 111, 100, 105, 110, 103); print pack("C*", @ascii)'

和上例我们看克unpack一个字串为值列表一样,我们也可以反过来他们pack回一个字串。 另一种方法,是利用chr函数,以码值为参数,返回相对应的字符:

perl -le '@ascii = (99, 111, 100, 105, 110, 103); print map { chr } @ascii'

和上面$55例相似,利用chr函数的map每一个@ascii的值为字符。

59.生成1到100所有奇数的数组。

perl -le '@odd = grep {$_ % 2 == 1} 1..100; print "@odd"'

本行代码生成从1到99的奇数组成的数组(1,3,5,7,9,…,99)。我们使用grep筛选列表1到100的各个元素,筛选代码用的是$_ % 2 ==。只有筛选代码评判为true的元素会返回。在本例中测试是否除2余数为1,如果是,这个数字为奇数,他会加到@odd数组中。 另外一种方法基于奇数具有低字节位为1的事实,并以此为测试:

perl -le '@odd = grep { $_ &amp; 1 } 1..100; print "@odd"'

表达式$_ & 1 分离出低字节位出来,并且grep筛选低字节位为1(奇数)。 关于字节见explanation of bit-hacks。

60.生成1到100所有偶数的数组

perl -le '@even = grep {$_ % 2 == 0} 1..100; print "@even"'

本行代码和上例基本上一样,除了grep test条件是偶数(能被2整除)。

61.计算字串的长度。

perl -le 'print length "one-liners are great"'

作为结束,length子程序返回字符串的长度。

62.计算数组元素个数

perl -le '@array = ("a".."z"); print scalar @array'

在标量上下文评估一个数组(或者哈希)的值会返回数组元素的数量。 另外一种计算方法是数组最后一个元素下表值加1:

perl -le '@array = ("a".."z"); print $#array + 1'

此处,$#array返回数组@array的最后一个元素的下标值,由于下标由0开始所以最后一个元素的下标比数组个数小1,所以通过加1就可以获数组的元素个数。

]]>
http://ijz.me/?feed=rss2&p=640 0
perl one-liners explained 中文版 (三)数值计算 http://ijz.me/?p=638 http://ijz.me/?p=638#respond Wed, 06 Aug 2014 11:58:03 +0000 http://ijz.me/?p=638 perl one-liners explained,是继《Famous Awk One-Liners Explained》和《Famous Sed One-Liners Explained》,后Peteris Krumin推出的又一个系列文章,并已经出书了。本blog会陆续对其进行翻译成中文,以便大家学习。本篇是第三部分——数值计算

原文地址:http://www.catonmat.net/download/perl1line.txt

原书blog地址:http://www.catonmat.net/blog/perl-book/

本翻译项目地址:https://github.com/bollwarm/perlonelinecn

数值计算

21.检查一个数字是否是质数

perl -lne '(1x$_) !~ /^1?$|^(11+?)1+$/ && print "$_ is prime"'

这行代码巧妙使用一个正则表达式判断给予的数字是不是质数。不要想得太复杂了,我引用这个例子主要为了说明其他的技巧性。首先,这个数字通过“1x$_”被转变为他一元表达式。例如,5被转化了“1×5”,也就是“11111”。接着,对这个一元表达式进行用独特的正则表达式进行匹配,如果不匹配这个数字是个质数,否则他就是是个合数。

这个正则表达式由两部分组成:“^1?$”和“^(11+?)1+$”。

第一个部分匹配“1”和空字符串。很明显,空字串和1不是质数,因此,这个表达式匹配了则表明这个数字不是一个质数。

第二部分检测是否两次或者更多次重复的1的组成了这个数字,正则匹配了,意味着数字由这样的多个1的重复组成的,否则的话,它是一个质数。

下面我们以5和6为例子,说明第二部分这个正则。

5的一元的表达式为“11111”。“(11+?)”首先会匹配两个1 “11”。后面引用“1”变成“11”,于是整个正则表达式变成了“^11(11)+$”。这个不会匹配11111,于是匹配失败。由于正则部分使用了“+?”,它会回溯,接着匹配三个1“111”。1于是变成了“111”这个正则表达式变成了“^111(111)+$”。这个也不会匹配。于是又重复用“1111”和“11111”匹配,当然也不会匹配。直到所有模式都尝试一遍都失败,因此这个数字是个质数。

数字6的一元表达式为“111111”。“(11+?)”首先匹配两个1 “11”,整个正则表达式为“^11(11)+$”。这个会匹配“111111”,所以数字不是一个质数。

“-lne”在第一部分和第二部分已经解释过,不再赘述。

22.打印一行中所有的域的和。

perl -MList::Util=sum -alne 'print sum @F'

这行代码使用了一个域自动切割的命令行选项“-a”,并且通过“-MList::Util=sum”引入了“List::Util”模块的“sum”求和函数。List::Util”模块是Perl核心模块,不需要担心额外安装的问题。

作为一个自动分割的结果,分割的域保存在“@F”数组中,“sum”函数只不过对其求和而已。-Mmodule=arg选项引入了一个模块,相当于语句use module qw(arg),这行代码相当于: use List::Util qw(sum);while (<>) { @F = split(‘ ‘); print sum @F, “n”;}

23.打印所有行所有域的值

perl -MList::Util=sum -alne 'push @S,@F; END { print sum @S }'

这行代码通过push操作把每行分割的@F数组保存到@S数组中去,当所有行都输入后,perl退出前END{}块被执行,调用sum函数对@S的所有成员求和。这个和就是所有行所有域的和。

这个方案不是最好选择。它生成了一个额外的数组@S,最好的方式是是下面的:

perl -MList::Util=sum -alne '$s += sum @F; END { print $s }'

24.以随机顺序显示每行的各个域。

perl -MList::Util=shuffle -alne 'print "@{[shuffle @F]}"'

本行和例22基本上相同,只不过本例使用shuffle函数将行域顺序随机打乱,并显示出来。

“@{[shuffle @F]}” 结构创建了一个指向“shuffle @F”内容的数组引用,并且通过“@ {…}”将其解引用成其内容。这是一个执行插入到引用中代码的常用技巧。这方法于我们需要把@F顺序打乱,并以空格分割输出是必须的。

另一种方法可以实现同样的功能,是通过join把@F的各个元素和空格连接起来,但是代码会更长一点:

perl -MList::Util=shuffle -alne 'print join " ", shuffle @F'

25.找到每一行的最小的元素

perl -MList::Util=min -alne 'print min @F'

本行代码使用了“List::Util”模块的“min”函数,形式和前面几例都相似。每行通过“-a”选项自动分割,并用“min”函数求出最小的元素并打印出来。

26.找到所有行中最小的元素。

perl -MList::Util=min -alne '@M = (@M, @F); END { print min @M }'

这行代码是上一例子以及例23的整合。“@M=(@M,@F)”结构相当于“push @M,@F”,把@F的内容附加到数组@M中。

本代码需要把所有数据都存进内存。如果你用它去处理10T大的文件,他肯定会挂掉。因此,因此更好一点的方法是只把最小等数存进内存,最后输出:

perl -MList::Util=min -alne '$min = min @F; $rmin = $min unless defined $rmin && $min > $rmin; END { print $rmin }'

代码会找出每一个行最小的一个并存进 $min,接着检查他是不是比当前最小数$rmin还小。最后打印当前最小数,保证了在所有的输人中他是最小的一个值。

27.找出一行中最大的数

perl -MList::Util=max -alne 'print max @F'

和例25完全相同,只不过函数用最大函数“max”。

28.找出所有行中最小的一个

perl -MList::Util=max -alne '@M = (@M, @F); END { print max @M }'

和例子26一样,也有另一种形式:

perl -MList::Util=max -alne '$max = max @F; $rmax = $max unless defined $rmax &amp;&amp; $max &lt; $rmax; END { print $rmax }'

29.对所有的域的值用其绝对值代替

perl -alne 'print "@{[map { abs } @F]}"'

本行代码,先通过“-a”命令行参数自动分割行的各个域,接着调用绝对值函数“abs”,通过map对其进行整体操作。最后利用匿名数组方式将各个域连接。@{ … }解释见例24.

30.找到每行域个数

perl -alne 'print scalar @F'

本行代码强制@F到标量上下文,这在perl中就是@F的元素个数。因此输出结果就是每行的域个数。

31.输出每行,并在每行前面显示域数量。

perl -alne 'print scalar @F, " $_"'

本例和例30基本上一样,除了把每行的内容“$_”也打印出来了。(提示,“-n”选项会导致进行输入循环,并把每行的内容存储在$_变量)。

32.计算所有行的域总数

perl -alne '$t += @F; END { print $t}'

在这我们仅仅通过把每行的域的数量累加,并用变量“$t”保存,最后输出。结果就是所有域的总数。

33.打印出匹配模式的域总数。

perl -alne 'map { /regex/ &amp;&amp; $t++ } @F; END { print $t }'

这行代码使用map函数对@F数组的各个元素进行操作。本例中是检查其是否匹配模式/regex/,如果是的话,给变量$t加1。在最后END模块中打印出$t的值,即为匹配的域的总数。

还有一种比较好的方法是:

perl -alne '$t += /regex/ for @F; END { print $t }'

每一个@F的元素用/regex/模式检验。如果匹配/regex/会返回值1(表示真),我们用+=操作符累加并赋值给$t.用这种方式使得匹配的数量会被保存在$t。 最好的方式是利用标量上下文的grep:

perl -alne '$t += grep /regex/, @F; END { print $t }'

在标量上下文grep会返回匹配的数量,数量也用$t进行累加。

34.打印所有匹配模式的行总数

perl -lne '/regex/ &amp;&amp; $t++; END { print $t }'

如果当前行输出匹配正则模式,/regex/为true。/regex/ && $t++相当于if ($_ =~ /regex/) { $t++ },如果模式匹配,$t值就会加1.最后END模块输出$t值,就是匹配模式的行的数量。

35.打印PI的值到n位小数点后。

perl -Mbignum=bpi -le 'print bpi(21)'

bignum库的bpi函数可以计算输出PI常量到所需足够精确地值。本例打印PI到小数点后20位。 bignum库也可以直接输出PI常量,这个数值保留39位的精确度:

perl -Mbignum=PI -le 'print PI'

36.打印E的值到n为小数点后。

perl -Mbignum=bexp -le 'print bexp(1,21)'

Bignum库也可以利用bexp函数,来计算和输出e及其n方幂的精确值,他的两个参数为幂值n以及精确位。本里打印了e的值(1一次方)到20位小数点后。

37.打印e的平方到31位精确值:

perl -Mbignum=bexp -le 'print bexp(2,31)'

和PI一样,binum也支持输出常量e,值也保持39位的精确度。

perl -Mbignum=e -le 'print e'

38.打印Unix 时间值(自从1970年一月一日, 00:00:00 UTC后累计秒的值)

perl -le 'print time'

内建的函数“time”返回公元以来的秒数。

39.打印GMT(格林威治时间)和本机时间。

perl -le 'print scalar gmtime'

“gmtime”函数是Perl内建的函数。如果使用标量上下文,他会打印格林威治时区(0时区)标准时间。

perl -le 'print scalar localtime'

“localtime”内建函数,表现和“gmtime”大致一样,不过他显示的计算机本地的时间。 “gmtime”和“localtime”均返回9元素的列表(tm结构体),包含下述元素:

($second,[0]$minute,[1]$hour,[2]$month_day,[3]$month,[4]$year,[5]$week_day,[6]$year_day,
[7]$is_daylight_saving[8])

根据实际的需要信息,你可以对此列表做切片,或者打印单个元素。例如,为了打印H:M:S,切割出localtime的2,1和0元素:

perl -le 'print join ":", (localtime)[2,1,0]'

40. 打印昨天的日期

perl -MPOSIX -le '@now = localtime; $now[3] -= 1; print scalar localtime mktime @now'

上例说了localtime返回一个9元素的各种时间项。其中第4项是当前日期数。如果我们对其减去1就得到昨天。“mktime”函数利用修改过的9项目列表构建一个Unix时间戳。最后“scalar localtime”打印了这个新的日期,就是昨天。

因为使用到了mktime函数,POSIX包是必须的,他应该是用于规范化负值。

41.打印14个月9天7秒前的日期

perl -MPOSIX -le '@now = localtime; $now[0] -= 7; $now[4] -= 14; $now[7] -= 9; 
print scalar localtime mktime @now'

本行代码修改了@now列表的第1个,第5个以及第8个元素。第1个是秒数,第5个是月,第8个是日(见上面时间9元素表). 接着利用mktime生成把它转化成了Unix时间戳,再利用标量上下文的localtime打印日期:14个月9天7秒钟前。

42.计算阶乘。

perl -MMath::BigInt -le 'print Math::BigInt-&gt;new(5)-&gt;bfac()'

本行代码使用Math::BigInt模块的bfac()函数,这个模块内置与Perl核心(不必另行安装)。

Math::BigInt->new(5)结构创建一个新的Math::BigInt对象,构造参数为5。接着用bfac()方法调用新创建的对象计算5的阶乘。如果计算其他数的阶乘,只需要在创建对象时候,更换构造参数的值为所希望的值即可。

另一种计算阶乘的方法是直接累乘从1到n的值:

perl -le '$f = 1; $f *= $_ for 1..5; print $f'

我们给$f初始化赋值为1.接着做一个从1到5的循环,对$f进行各个值的累乘。结果是12345,这就是5的阶乘。

43.计算最大公约数。

perl -MMath::BigInt=bgcd -le 'print bgcd(@list_of_numbers)'

Math::BigInt还内带有其他好多个非常有用的数学函数。这其中之一是bgcd,用来计算一列数字的最大公约数。

perl -MMath::BigInt=bgcd -le 'print bgcd(20,60,30)'

当然,你也可以使用欧几里德算法(即辗转相除法)。给予两个数字$n和$m,这行代码找出两者的gcd。结果保存在$m中。

perl -le '$n = 20; $m = 35; ($m,$n) = ($n,$m%$n) while $n; print $m'

44.计算最小公倍数。

另外一个函数是lcm,计算最小公倍数,一下行代码计算(35,20,8)的最小公倍数。

perl -MMath::BigInt=blcm -le 'print blcm(35,20,8)'

如果你了解一些数字定理,你应该能知道gcd和lcm之间是有联系的。给定两个数字$n和$m,他们的lcm等于$n*$m/gcd($n,$m),因此,也就是另一种计算最小公倍数的行代码:

perl -le '$a = $n = 20; $b = $m = 35; ($m,$n) = ($n,$m%$n) while $n; print $a*$b/$m'

45.生成5到15之间(包括15)的10个随机数

perl -le '$n=10; $min=5; $max=15; $, = " ";print map { int(rand($max-$min))+$min } 1..$n'

你能通过改变$n,$min,$max调整此行代码。变量$n表示要生成多少个随机数,[$min,$max)表示生成数的访问。

变量$,设为空格,用来格式化输出的域间隔,默认没有设置。所以如果我们不设置它为空格,打印的数字将会连在一起。

46.找出列表的所有排列方式并打印出来。

perl -MAlgorithm::Permute -le '$l = [1,2,3,4,5]; $p = Algorithm::Permute->new($l);
print @r while @r = $p->next'

这行代码使用面向对象的接口Algorithm::Permute模块来找出排列(所有重新组合元素的方法)。

Algorithm::Permute的构造方法接受一个数组引用参数来排列。本例中元素为1,2,3,4,5。

对象方法的方法next返回下一个排列。循环调用这个方法可以获得所有可能的排列。

我们可以注意到很快就能输出大量的列表。对一个n个元素的列表来说有n!种排列。

另一种方法是使用permute子函数。

perl -MAlgorithm::Permute -le '@l = (1,2,3,4,5);Algorithm::Permute::permute { print "@l" } @l'

47.生成幂集。

perl -MList::PowerSet=powerset -le '@l = (1,2,3,4,5); for (@{powerset(@l)}) { print "@$_" }'

本例,我使用了CPAN的List::PowerSet模块。我输出powerset函数,本函数以一列表做为参数,返回一个引用,该应用为指向子集列表的引用的列表。 在for循环调用了powerset函数,传递给它@l的列表元素。接着,解引用返回powerset的值,这个值是一个指向子集列表的引用。最后,解引用每一个子集@$_并打印它。

对一个n元素的集合,他的幂集有2n个子集。

48.转换IP地址为无符号整数。

perl -le '$i=3; $u += ($_&lt;&lt;8*$i--) for "127.0.0.1" =~ /(d+)/g; print $u'

本行代码转换127.0.0.1的IP地址为无符号整数(他恰巧是2130706433)。

首先对IP地址做了个(d+)全局匹配。做一个for循环做全局匹配的迭代,使所有数字得到匹配,匹配了IP地址的四个部分。 接着把匹配的数字加起来保存在$u中,其中第一部分位移83=24位,第二部分位移28=16位,第三部分8位,最后一部分直接加给$u。 但是本行代码没有对IP地址做任何的格式检验。你也可以使用一个更复杂一点正则表达式来检测,比如/^(d+).(d+).(d+).(d+)$/g。 经过和朋友一起讨论,我们想出另外一些方法:

perl -le '$ip="127.0.0.1"; $ip =~ s/(d+).?/sprintf("%02x", $1)/ge; print hex($ip)'

这个行代码巧妙地利用127.0.0.1可以被容易的转化为十六进程 7f000001的事实,再利用Perl的hex函数转化为十进制。

另一种方法是利用unpack:

perl -le 'print unpack("N", 127.0.0.1)'

这个行代码大概是能达到最短的一个。它利用vstring语法(版本字符)表达IP地址。Vstring格式是指用特定顺序值组成的字符串。接着,利用网络字节顺序(Big-Endian顺序)新的格式化字符串被解包为一个数字,并把它打印出来。

如果有一个IP的字符串(不是一个vstring),你首先就要用inet_aton函数转化这个字符串为字节的形式:

perl -MSocket -le 'print unpack("N", inet_aton("127.0.0.1"))'

这儿inet_aton函数转化字符串“127.0.0.1 ”为字节的形式(这恰恰和纯vstring 127.0.0.1是一样的),接着unpack它。

49.转化一个无符号整数为IP地址。

perl -MSocket -le 'print inet_ntoa(pack("N", 2130706433))'

本例中整数2130706433首先被pack为一个Big-Endian数字,并且利用inet_ntoa函数转化这个数字为IP地址。

另外一种方法是用位移和逐字节打印的方式:

perl -le '$ip = 2130706433; print join ".", map { (($ip>>8*($_))&0xFF) } reverse 0..3'

随便说一下,join “.”可以被特殊变量$,代替,它专门用来做为打印语句的默认分割符:

perl -le '$ip = 2130706433; $, = "."; print map { (($ip>>8*($_))&0xFF) } reverse 0..3'

 

]]>
http://ijz.me/?feed=rss2&p=638 0