perl实现grep,awk,sed功能的方法介绍

发布时间:2020-03-25编辑:脚本学堂
perl实现grep,awk,sed功能的方法介绍,供大家学习参考。

perl实现grep,linuxjishu/13830.html target=_blank class=infotextkey>awk,sed功能的方法介绍,供大家学习参考。

pattern比对    (grep)
字符串 命令 /pattern/修饰词
命令
=~   表示比對符合pattern
!~   表示比對不符合pattern
修饰词
i 不計大小寫
x 在模式中忽略空格
g 继续比对,继续寻找,相当于find next
   例子  :扫描文件gogo,找含有want的行
 

复制代码 代码如下:

#!/usr/bin/perl

$file="/home/macg/perltest/gogo";
&gotest($file);

sub gotest{
my(@tmp)=@_;

open (MYFILE, $tmp[0]) || die ("Could not open file");
my($line,$newline);
while ($line=<MYFILE>) {
if($newline=($line=~/want/)) { #行中查找含有want
  print "foundn";
  print "$line is:$line";
  print "$newline is:$newline n";
 } else {
  print "not foundn";
  print "$line is:$line";
  print "$newline is:$newline n";
    }
  }
close(MYFILE);
}   
 

[macg@localhost perltest]$ ./tip.pl
not found
$line is:I glad to be Los angle
$newline is:
found
$line is:I want to be Los angle
$newline is:1

缺省的,模式定界符为反斜线/,但其可用字母m自行指定,如:
m!/u/jqpublic/perl/prog1!    等价于    //u/jqpublic/perl/prog1/
而且换成其他字符后,/就不属于特殊字符了,不必加/了

pattern
d或d+      任意数字 [0-9]
D或D+     除数字外的任意字符 
/[da-z]/   等同于/[0-9a-z]/
^    /^def/  只匹配以def打头的字符串
$   
//         转义字符
/*+/
             pattern中标点都要加
[]           意味着匹配一组字符中的一个
* + ? .      通配符

*+不能作为首字符,所以任意字符必须用显示表示法[0-9a-zA-Z]
$line=~
syntax error at ./address.pl line 6, near "out @int_hwaddress"
Quantifier follows nothing in regex; marked by <-- HERE in m at ./address.pl line 41
改为
$line=~/[0-9a-zA-Z]+:[0-9a-fA-F]+:[0-9a-fA-F]+:[0-9a-fA-F]+:[0-9a-fA-F]+:[0-9a-fA-F]+/
.

pattern中空格就是" "
if(($input=~/^ping$/i)||($input=~/^ping $/i))
macg>ping
command:[ping xxx.xxx.xxx.xxx]
macg>ping                      带一个空格
command:[ping xxx.xxx.xxx.xxx]
IEI-nTracker>ping               带两个空格
Use of uninitialized value in concatenation (.) or string at /nettracker/ntshell/ntshell
 
if(($input=~/^ping$/i)||($input=~/^ping +$/i))
IEI-nTracker>ping     多个空格
command:[ping xxx.xxx.xxx.xxx]

if($_[0]=~/^ping +[0-9a-zA-Z.]+$/i)
相当于"ping xxxxx"或"ping        xxxx"

=~/want/是等于,还是含有?
当然是包含
等于其实就是exactly匹配,/^wang$/

格式匹配(不是包含性符合),通常用于一些特殊格式输入时用(比如IP地址
 

复制代码 代码如下:

#!/usr/bin/perl

$file="/home/macg/perltest/gogo";
&gotest($file);

sub gotest{
my(@tmp)=@_;

open (MYFILE, $tmp[0]) || die ("Could not open file");
my($line,$newline);
while ($line=<MYFILE>) {
if ($line =~ /d+.d+.d+.d+/) {
  print "$line";
  print "the ip add is goodn";
 } else {
  print "$line";
  print "the ip add is a errorn";
    }
  }
close(MYFILE);
}  
 
 

[macg@localhost perltest]$ cat gogo
202.106.0.20
10.0.0.as

[macg@localhost perltest]$ ./tip.pl
202.106.0.20
the ip add is good
10.0.0.as
the ip add is a error
上面这个例子也不对,会出下面的错:包含以外的错误,所以应该加^ $
[macg@localhost perltest]$ cat gogo
202.106.0.20
10.0.0.as
10.0.0.1 as  
改成 if ($line =~ /^d+.d+.d+.d+$/) {
[macg@localhost perltest]$ ./tip.pl
202.106.0.20
the ip add is good
10.0.0.as
the ip add is a error
10.0.0.1 as
the ip add is a error  

/want/g与/want/的区别:指针后移,相当于find next
 

复制代码 代码如下:
$line="inet addr:192.168.10.17  Bcast:192.168.10.255  Mask:255.255.255.0";
$line=~/(d+).(d+).(d+).(d+)/;
print "$&n";       $&查询结果
$line=~/(d+).(d+).(d+).(d+)/;
print "$&n";
$line=~/(d+).(d+).(d+).(d+)/;
print "$&n";

[root@nm testpl]# ./tip.pl
192.168.10.17
192.168.10.17
192.168.10.17
几次的查找都相同,因为每次都是回到“首部”找“一次”
找到一个,就返回值1,并停止比对
加g
 

复制代码 代码如下:
$line="inet addr:192.168.10.17  Bcast:192.168.10.255  Mask:255.255.255.0";
$line=~/(d+).(d+).(d+).(d+)/g;
print "$&n";
$line=~/(d+).(d+).(d+).(d+)/g;
print "$&n";
$line=~/(d+).(d+).(d+).(d+)/g;
print "$&n";

[root@nm testpl]# ./tip.pl
192.168.10.17
192.168.10.255
255.255.255.0 
加g后,好象文件指针一样,查一次,指针就移一格

“或”下的比对,匹配的先后顺序很重要, 尤其是包含型的,要把精确的放前面
 

复制代码 代码如下:
if (($ret=($line=~/eth[0-5]/))||($ret=($line=~/eth[0-5]:[0-5]/)))
 {
print "$&:";
$found=1;
 } elsif ($found)
  {
  print $line;
  $found=0;
  }
}

[mac@nm testpl]$ ./address.pl
eth0:          inet addr:10.4.3.117  Bcast:10.4.255.255  Mask:255.255.0.0
eth0:          inet addr:192.168.10.117  Bcast:192.168.10.255  Mask:255.255.255.0
eth0:          inet addr:192.168.1.142  Bcast:192.168.1.255  Mask:255.255.255.0
eth1:          BROADCAST MULTICAST  MTU:1500  Metric:1
改成精确的放前面
if (($ret=($line=~/eth[0-5]:[0-5]/))||($ret=($line=~/eth[0-5]/)))
[mac@nm testpl]$ ./address.pl
eth0:          inet addr:10.4.3.117  Bcast:10.4.255.255  Mask:255.255.0.0
eth0:1:          inet addr:192.168.10.117  Bcast:192.168.10.255  Mask:255.255.255.0
eth0:2:          inet addr:192.168.1.142  Bcast:192.168.1.255  Mask:255.255.255.0
eth1:          BROADCAST MULTICAST  MTU:1500  Metric:1
先查到精确,就会跳过模糊的(部分的),否则会用模糊的(部分的)代替精确的。

$line =~ /want/ 完成,只返回1和null
即比对不修改=~左边字符串
与比对截然不同,替换是修改=~左边字符串的
 

复制代码 代码如下:
my($line,$newline);
while ($line=<MYFILE>) {
if($newline=($line=~/want/)) {
  print "foundn";
  print "$line is:$line";
  print "$newline is:$newline n";
 } else {
  print "not foundn";
  print "$line is:$line";
  print "$newline is:$newline n";
    }
  }
close(MYFILE);
}  
 

[macg@localhost perltest]$ ./tip.pl
not found
$line is:I glad to be Los angle
$newline is:
found
$line is:I want to be Los angle
$newline is:1

如何能找到比对结果?    用$&
 

复制代码 代码如下:
while ($line=<MYFILE>) {
if ($line =~ /want/) {
  print "$line";
  print "$& is $&n";
  print "goodn";
 } else {
  print "$line";
  print " errorn";
    }
  }  

[macg@localhost perltest]$ ./tip.pl
I want go to LA. and I also want to be NY.       $line没发生变化
$& is want                         $&是比对结果
good
But I glad to be D.C.
 error  

注意if ($line=~/want/)和赋值毫无关系,所以不存在$line值改变的问题,$line只是操作符号=~左边的一个元素而已,所以也不存在返回值给$line的问题
$&     $`      $' 的含义
 

复制代码 代码如下:
while ($line=<MYFILE>) {
if ($line =~ /want/g) {
  print "goodn";
  print "$line";
  print  $& . "n";
  print  $` . "n";
  print  $' . "n";
  print "goodn";
 } else {
  print " errorn";
  print "$line";
    }
  } 
 

[macg@localhost perltest]$ ./tip.pl
good
I want go to LA. and I also want to be NY.
want                  $&      $&是最后一个match,也可算是结果
I                      $`       match之前的所有字符
 go to LA. and I also want to be NY.    $'      match之后的所有字符

 !~ 比对不符合pattern      (其实没什么用,因为用if ( =~ ) else即可)

perl可以将pattern再细分 ,再用$1,$2,$3,$4表示这些子match
步骤:
1.对想单独提出来的子pattern加( )
2.再用$1,$2来表示
 

复制代码 代码如下:
if ($line =~ /^(d+).(d+).(d+).(d+)$/) {
  print "good n";
  print $line;
  print  $& . "n";
  print $1,"n";
  print $2,"n";
  print $3,"n";
  print $4,"n";
 

[macg@localhost perltest]$ ./tip.pl
good
202.106.0.20
202.106.0.20
202
106
0
20 

修饰词i          不计大小写
 

复制代码 代码如下:
if ($line =~ /want/i) {
  print "good n";
  print $line;
  print  $& . "n";
 

[macg@localhost perltest]$ ./tip.pl
good
I WANT TO go to
WANT 

修饰词x 在模式中忽略空格
/d{2} ([W]) d{2} 1 d{2}/x  等价于  /d{2}([W])d{2}1d{2}/

替换格式
命令与修饰词基本上与比对相同
格式: string command  s/pattern/欲置換的字串/修饰词
命令与比对相同
=~          先比对符合(=~)再替换
!~          比对不符合(!~)再替换


基本替换(后面替换前面)
$line =~s/want/hate/i;
  print "good n";
  print "$line is :$line";
  print "$& is : $&", "n"; 
[macg@localhost perltest]$ ./tip.pl
good
$line is :I hate TO go to    与比对截然不同,替换是修改=~左边字符串的
$& is : WANT      替换里的$&和就是比对的$&
 
修饰词i,不计大小写
$line =~s/want/hate/i;    將 $line中的 want 或 WANT,Want 換成 hate

刪除(替换为空)
单纯的删除一般没用,实际应用中,基本上都用全域删除(g)

$line =~s/want//i;
  print "$line is :$line";
[macg@localhost perltest]$ ./tip.pl
$line is :I  TO go to
  
g全域替换,替换所有的,缺省替换是查找到第一符合的就替换,然后停止
$line =~s/want/hate/ig;       修饰词可以连写
  print "good n";
  print "$line is :$line"
[macg@localhost perltest]$ cat gogo
I WANT TO go to NY. And I also want to be DC.
I glad to go to 

[macg@localhost perltest]$ ./tip.pl
$line is :I hate TO go to NY. And I also hate to be DC.

替换g与比对的g的不同

比对g是find next,所以需要与while等合用
替换不需要用循环语句,一句就能实现所有替换,即:替换不需要find and find next,替换可以find all in one time.


e选项把替换部分的字符串看作表达式,在替换之前先计算其值
$string = "0abc1";
$string =~ s/[a-zA-Z]+/$& x 2/e;  将中间的字符(非数字)成倍
now $string = "0abcabc1"
$&是查找结果
   
转换格式
string command tr/字元集/欲轉換的字元集/修饰词
string command y/字元集/欲轉換的字元集/修饰词
命令:=~  !~
修饰词:
d 刪除
s 將重覆刪除
c 非转换:將不在指定字元集中的字元(包括換行字元),換成欲轉換的字元集

最基本的转换:字符串小写换大写
$line =~tr/a-z/A-Z/;
print "$line is :$line";
[macg@localhost perltest]$ cat gogo
I WANT TO go to NY. And I also want to be DC.
 
[macg@localhost perltest]$ ./tip.pl
good
$line is :I WANT TO GO TO NY. AND I ALSO WANT TO BE DC.  
转换和替换一样,也是修改string
 
删除: =~tr/要删除的字符//d

全域替换删除和转换删除等价
全域替换删除    $line =~tr/t//g;
转换删除        $line =~tr/t//d;
$line =~tr/t//;            删除所有TAB  转化所有TAB为空//
print "$line is :$line";
[macg@localhost perltest]$ ./tip.pl
$line is :I WANT TO              go to NY. And   I also want to be DC.           
发觉TAB没删掉,其实不是没删掉,只是只删了第一个TAB而已
$line =~tr/t//d;
print "$line is :$line";
[macg@localhost perltest]$ ./tip.pl
good
$line is :I WANT TO go to NY. And I also want to be DC.

删除重复字符:   =~ tr/a-zA-Z//s;  这功能没什么实际用途
$line=~ tr/a-zA-Z//s;
  print "$line is :$line"; 
[macg@localhost perltest]$ cat gogo
I WANTWANT TO go to NNYY. And I also wWant to be DC. 
[macg@localhost perltest]$ ./tip.pl
good
$line is :I WANTWANT TO go to NY. And I also wWant to be DC. 

tr转换不支持!~  只支持=~      因为修饰词c就相当于!~了
$text="1 abc 23 PID";
$text =~ tr/[0-9]c;      [0-90]c即非数字
 
一个CGI控件值的解码的示范程序:
$value="%A4T%A4K%21";
$value=~s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
s替换%字符串,
并把符合的字符串传给$1,
把$1通过e运算pack("C",hex($1))进行解码处理
pack("C",hex($1))把$1找到的十六进制数值转成十进制的码
C代表unsigned char value的意思。