您的位置:首页 > 运维架构

Perl 学习

2013-03-02 08:28 218 查看
1、块注释,You can read more about POD in perldoc perlpod.
=begin comment
This content is commented out.

It may span many lines.

print "This statement won’t be executed by Perl\n";
=end comment
=cut

print "Hello world!\n"; # print the message
第一个“=”和“=cut”之间为注释部分。
2、使用__END__(2个_),__END__下面的部分都会被perl忽略,一般用于在perl代码中添加大量的文档。

print "Hello world!\n"; # print the message

__END__

All text and code from here downwards will be ignored by Perl.

print "This statement won’t be executed by Perl\n"
20100223
1、<>被用来处理所有的输入
尖括号操作(<>)是一种特殊的行输入操作。其输入可由用户选择,可能是从键盘,或者不是。
举个例子,最简单的,打印输入(其实和cat是一样的功能)
#!/usr/bin/perl
while(<</SPAN>>){

        print;

}
我们可以在命令行中直接输入:
./print.pl read.txt 
而不需要
cat read.txt|print.pl


一个程序的调用参数(invocation
arguments),通常是命令行中程序名字后面的一些“字符串”。下例中,它们是要被顺序处理的文件的名字:
./print.pl read.txt read2.txt read3.txt
将运行 print.pl(在当前目录下),它将处理文件 read.txt,再处理文件 read2.txt,最后是文件read3.txt。
如果没有命令行参数,程序将处理标准输入流.

技术上讲,<>从数组@ARGV中得到调用参数。这个数组是Perl 中的一个特殊数组,其包含调用参数的列表。

另:

由于 print 需要一些输出的字符串列表,则其参数是作为列表 context 来求值的。由于<>操作返回的是列表,则它们可很好的一起工作:
print <>; # ‘cat’ 的源程序
print sort <>; #‘sort’ 的源程序

20100302
1、特殊变量$^I

变量$^I。默认时为 undef,此时没有什么特殊的地方。但给它设置某些串时,它使尖括号操作(<>)变得有些特殊。

我们知道尖括号(<>)的神奇特点:如果没有指定文件名,则其从标准输入流中自动打开和关闭一系列文件进行读入。但如果$^I中有字符串,这个字符串则会成为备份文件的扩展名。

#! /usr/bin/perl – w

use strict;

chomp(my $date = ‘ date’ );

$^I =“ .bak”;

while(<</SPAN>>){

s/^Date:.*/Date: $date/;

print;

}
假设此时尖括号(<>)打开的文件是 fred03.dat。它像以前那样打开它,但进行了重名名,把它叫做fred03.dat.bak。这很好,因为不在使用之前的名字。现在<>将这个新的文件作为默认的输出,因此任何内容将输出到那个文件中。while循环会从旧的文件中读入一行,更新它,再把它输出到新文件中。

$^I 另一个可能值是空串,这会修改文件,但不会将原来的文件进行备份。

20100304:
1、对 _ 这个文件句柄(此操作数为单个下划线)进行文件检测(file test),stat,
或lstat操作时,将要求Perl对前一个文件检测(file test), stat,或lstat函数的操作数进行操作,而非再一次的进行系统调用。

my @original_files = qw/ fred barney bettyWilma pebbles dino bam-bamm/;

my @big_old_files; #需要移到备份磁带上去的文件

foreach(@orginal_files){

blei@163.com 146 / 201 9/21/2006
push @big_old_files, $_
if (-s) > 100_100 and –
A _ > 90; #比以前的方法效率高

}
第一次检测时使用了默认的变量$_。这也更加有效率(可能除了对程序员之外),他从操作系统中得到数据。第二次检测使用了 _ 这个文件句柄。这次检测中,使用第一次检测的文件的大小信息,这是我们所需要的。
对文件句柄 _ 进行检测不同于对$_进行检测。使用$_,可能每一次的值均不同,其为当前$_中得值,使用 _ 是为了解决重复调用系统的问题。

20100429:

open F, “ find / -atime +90
 –print|”or die “ fork: $!” ;
while(<</SPAN>F>) {

chomp;

printf %s size %dK last accessed on %s\n” ,

$_, (1023 + -s $_)/1024, -A
$_;

}
这个例子中的find 命令查找所有在最近90天没有访问。(它们是被备份的好对象)当find 查询时,Perl等待。每当找到时,Perl会将其名字,以及一些其它信息显示出来以供进一步的分析。如果用反引号来做,我们在find命令执行完之前是得不到任何输出的。通常在没有结束前就看见它在工作是很舒服的。

20100506:
给进程组发信号:
进程是组织成进程组的,一起对应一个完整的任务。比如,如果你运行了单个 shell 命令,这条命令是有一系列过滤器命令组成,相互之间用管道传递数据,这些进程(以及它们的子进程)都属于同一个进程组。(即子进程和父进程)
如果你给一个正数的进程号发送信号,该信号只发送给该进程,而如果你给一个负数进程号发送信号,那么该信号将发送给对应的进程组的所有进程,该进程组的进程组号就是这个负数的绝对值。
如:停止所有以941为父进程的进程:
perl -e "kill(HUP, -941);"
20100525:
关于时间格式
perl -e 'use Date::Format; print time2str("%Y%m%d %T", time+86400);'
time2str 由Date::Format提供,+86400表示1天以后的时间,更多的格式查看perldoc Date::Format

perl -e 'use Date::Format;use
Date::Parse; print time2str("%Y%m%d %T", str2time("24/May/2010:00:00:19"));'
str2time 由Date::Parse提供

20100602
将perl用于shell数字的循环
        for i in `perl -e 'for(0..9){print
"$_ "}'`
do
....
done

        for i in `perl -e 'for(00..31){$num=sprintf "d",$_;print "$num "}'`
do
....
done

for i in `perl -e 'for(00..31){print(sprintf "d ",$_)}'`
do
.....
done
shell 实现同样功能(详细查看man seq)
for i in `seq -s ' ' 01 31`;do printf "d " $i;done
do 
echo $i
.....
done
20100802
打印当前时间

use Date::Format;

print time2str("%Y%m%d-%T",time);

use Date::Parse;

use Date::Format;

print time2str("%Y%m%d-%T",str2time(ctime(time)));
20100831
打印某个时间段的时间,可以设定输出的格式

use Date::Format;

use Date::Parse;

use strict;

my $start=shift;

my $end=shift;

my $add_seconds;

my $output_format;

my $time_length=length $start;

if ($time_length eq 13 ){

    #loop hour

    $add_seconds=3600;

    $output_format="%Y-%m-%d %H";

}elsif($time_length eq 10){

    #loop day

    $add_seconds=3600 * 24;

    $output_format="%Y-%m-%d";

}else{

    die "Wrong input format:\nloop day: YYYY-mm-dd\nloop hour: YYYY-mm-dd-HH";

}

my $start_in_UTC=str2time($start);

my $end_in_UTC=str2time($end);

die "Wrong,$start later than $end" if $start_in_UTC gt $end_in_UTC;

my @all;

while ($start_in_UTC le $end_in_UTC){

    my $this_time=time2str("$output_format",$start_in_UTC);

    push @all,$this_time;

    $start_in_UTC=$start_in_UTC + $add_seconds;

}

map {print "\"$_\" "} @all;

shell版本查看:http://blog.chinaunix.net/space.php?uid=1838361&do=blog&id=3079565

20101103
perl正则表达式中的\1 \2 \3
使用捕获的buffers
例如:
/(\w)\1/;
匹配包含两个word的字符串。 \1 表示第一个()所捕获的\w

/(\w)\1+/; 匹配包含两个或两个以上的字符串。

嵌套捕获时,需要注意要重复的捕获的()
/((\w)\2){2,}/;  注意:捕获变量的顺序按照“开括号(”的顺序指派,不管嵌套与否。

20101112:
perl 调用shell内置命令:
通常可以使用system函数或者``来执行系统命令,但是对于shell的内建命令(如alias,ulimit等,详细查看 man -k bash),这样执行时会直接报错,错误内容为无法找到文件或目录,可以通过bash -c来执行这样的命令。而对于cd、umask等命令,应该使用PERL函数chdir、umask等来实现

20101115:
1、修改配置文件:
$selinux_file="/etc/selinux/config";

tie(@data,Tie::File,$selinux_file,autodefer
=>0) or die $!;

#(tied @data)->defer; 

foreach (@data) {

        s/enforcing/disabled/g if grep {/SELINUX/} $_;

}
#(tied @data)->flush
Normally, modifying a Tie::File array writes to the underlying file immediately. Every assignment like $a[3] = ... rewrites
as much of the file as is necessary; typically, everything from line 3 through the end will need to be rewritten. This is the simplest and most transparent behavior. Performance even for large files is reasonably good.
However, under some circumstances, this behavior may be excessively slow.
autodefer =>0 
Tie::File tries to guess when deferred writing might be helpful, and to turn it on and off automatically.

或:

Open the file in update mode ("+<"), read the whole file into an array of lines, change the array, then rewrite the file and truncate it to its current
seek pointer.

 

open(F, "+<", $infile) or die "can't
read $infile: $!";

$out = "";
while (<</SPAN>F>) {

    s/DATE/localtime/eg;

    $out .= $_;

}

seek(F, 0, 0) or die "can't
seek to start of $infile: $!";

print F $out or die "can't print to $infile: $!";

truncate(F, tell(F)) or die "can't
truncate $infile: $!";

close(F) or die "can't close $infile: $!"

2、包含递归调用

#3.disable selinux
sub selinux_config {

        print "\nDo you want to disable SELINUX [y/n]:";

        given (chomp($answer=<</SPAN>>)){

                when ($answer ~~ /^y(?:$|es$)/i){

                        $selinux_file="/etc/selinux/config";

                        tie(@content,Tie::File,$selinux_file,autodefer => 0) or die
$!;

                        foreach (@content) {

                        s/enforcing/disabled/g if grep {/SELINUX=/} $_;

                        }

                        system("/usr/sbin/setenforce 0 ");

                        print "SELINUX is disabled,you didn't need to reboot.\n";

                }

                when ($answer ~~ /^n(?:$|o$)/i){print "SELINUX
still on\n"}

                default {

                        print "UNKNOW RESPONSE\n";

                        &selinux_config ;

                };

        };

}

&selinux_config
20101116:

1、Use map  when you need to transform one list into
another.

Use grep  to filter a list.
Use foreach  when you want to modify the variable in-place.


20101118:
Use Perl::Tidy  to beautify code
echo "install Perl::Tidy"|perl -MCPAN -eshell
使用,例如:ugly.pl

use warnings; use strict;
while(<</SPAN>>) { if(/\d/
) { print "contains number\n"; }
else { print "number-free\n" } }
执行: perltidy ugly.pl
结果为:ugly.pl.tdy
use warnings;

use strict;
while (<</SPAN>>) {
  if  (/\d/) { print "contains
number\n"; }
  else       { print "number-free\n" }

}
配置Perl::Tidy,例如,更改缩进为4,更改输出为stdout,而不是.tdy
perltidy -st -i=4  ugly.pl

bracing style
perltidy -st -bl -bli ugly.pl

 
use warnings; 
use strict; 
while (<>)
  {
      if   (/\d/) { print "contains number\n"; } 
      else        { print "number-free\n" }
  }
By default, Test::PerlTidy  uses the standard options. If you want your 
code formatted with different options, ensure that you have a .perltidyrc 
file in the root of your distribution or in your home directory.

20101220
scp、ssh 可以使用密码来验证的模块:
Net::OpenSSH

#3、scp files

my $ssh = Net::OpenSSH->new(

                        $host,

                        user => $user,

                        password => $password,

                );

die "Can't ssh to $host: " . $ssh->error
if $ssh->error;

$ssh->scp_put({quiet => 0,recursive => 1},"$backup_file","$remote_dir");

#4、rm remote host old files

$ssh->system("find $remote_dir -mtime
+20 -name project*|xargs rm")

另外两个模块也可以实现:
scp 可以使用密码来验证的模块:
Net::SCP::Expect

ssh,使用密码来验证

Net::SSH::Expect


 Net::SSH::Perl

#3¡;¢scp files
if (-e $backup_file){

        print "tar file ok\n";

        my $scpe = Net::SCP::Expect->new(host=>"$host", user=>"$user",password=>"$password");

        $scpe->scp("$backup_file","$remote_dir");

}else{

        print "tar file false\n";

}

#4¡;¢rm remote host old files

my $ssh = Net::SSH::Expect->new (

            host => "$host",

            user => "$user",

            password => "$password",

            raw_pty => 1

        );

my $login_output = $ssh->login();

die "Login has failed. Login output was: $login_output" if $login_output !~ /Last
login:/;

my $find_rm = $ssh->exec("find
$remote_dir -mtime +20 -name project*");

#print "$find_rm\n";

$ssh->close()
20101221
使用匿名函数打印当前时间
创建匿名函数

use Date::Format;
my $current_time=sub {

        time2str("%Y%m%d-%T",(time))

};

print &$current_time."\n"

20101228
对于while阻塞perl,可以将改while放到一个异步程序中,由调用程序来kill掉调用程序。
或者使用fork子进程来解决,查看:
http://blog168.chinaunix.net/space.php?uid=1838361&do=blog&id=66643

20110105
改变终端输出的颜色
Use the CPAN module Term::ANSIColor to send the ANSI color-change
sequences to the user's terminal:

use Term::ANSIColor qw(:constants);
print RED, "Danger, Will Robinson!\n", RESET;

20110111
File::Copy
The File::Copy module provides two basic functions, copy and move ,
which are useful for getting the contents of a file from one place to another.

20110130
关于在perl的system()中echo “@”

system ("echo @")

这样写的话@会被当做数组的@符号,达不到目的,应该用下面两种方法来写:

@args=("echo","@");
system(@args);

$a='@';
system("echo $a");

20110302
数据库连接的模块

#@ _MODULE_INITIAL_
package Cookbook;
# Cookbook.pm - library file with utility method for connecting to MySQL
# via Perl DBI module
use strict;
use warnings;
use DBI;
my $db_name = "cookbook";
my $host_name = "localhost";
my $user_name = "cbuser";
my $password = "cbpass";
my $port_num = undef;
my $socket_file = undef;
# Establish a connection to the cookbook database, returning a database
# handle. Raise an exception if the connection cannot be established.
sub connect
{
my $dsn = "DBI:mysql:host=$host_name";
my %conn_attrs = (PrintError => 0, RaiseError => 1, AutoCommit => 1);
$dsn .= ";database=$db_name" if defined $db_name;
$dsn .= ";mysql_socket=$socket_file" if defined $socket_file;
$dsn .= ";port=$port_num" if defined $port_num;
return (DBI->connect ($dsn, $user_name, $password, \%conn_attrs));
}
#@ _MODULE_INITIAL_
#@ _MODULE_END_
1; # return true
#@ _MODULE_END_

注:模块文件最后一行总是返回true的语句,这是必须的。因为如果模块没有返回一个true值,perl会假设模块出现了错误,并在读取它之后退出。
将改文件放到/opt下,添加到环境变量中

export PERL5LIB=/opt
使用

#!/usr/bin/perl -w
use strict;
use Cookbook;
my $dbh;
eval
{
$dbh=Cookbook::connect();
print "Connect!\n";
};
die "$@" if $@;
$dbh->disconnect();

20110315
摘自《perl最佳实践》

if(/^(\d+) (\D+)$/)

改为

if(m{^(\d+)
#匹配数字

       (\D+)$
  #匹配非数字

   }xms)

其中:/x模式可以让正则表达式以较具可维护性的方式进行部署及说明。在/x模式下,正则表达式里的空白会被忽略掉,所以你可以人随意使用空白和换行字符以缩排和部署
需要注意的是,这样的话,数据里的空白就要用\s来匹配,而不能使用“ ”来匹配
/m,在sed,awk,grep等重,^,$指“匹配任何行的开头及末尾”,但在perl中,指的是“匹配整个字符串的开头和结尾”,使用/m,可以使perl中的行为与上面的程序的行为一致。
/s,点号元字符(.)在perl中兵不是“匹配任何字符”,因为点号元字符并不匹配换行字符,使用/s可以视其也匹配换行符。

下面是一个access log日志的例子

if (m{^((?:\d{1,3})\.(?:\d{1,3})\.(?:\d{1,3})\.(?:\d{1,3})) #ip

        \s* - \s - #nothing

        \s* \[(.*?)\] #time

        \s* "GET\s /(?:\w)+/www/delivery/ta\.php\?trackerid=(\d+)(\D*[\d\D]*) #url

        \s* HTTP\/1\.[01]" #proto

        \s* \d+ \s \d+ #status
byte

        \s* "(?:.*?)" #refer

        \s* "(?:.*?)" #agent

        \s* "([A-Z0-9]{16,21})"$ #guid

     }xms){

一个例子,取出url中的域名的域

if ($url=~m{http://

                          (

                          [^.\s]+

                          \.(?:com|net|org|gov|cc|biz|info|cn|tv)

                          (?:\.cn|\.hk)

                          )

                    }xms) {

                        print "$1\n";

                }

  elsif($url=~m{http://

                          (?:[^.\s]+\.)?

                          (

                          [\S\.]+

                          \.(?:com|net|org|gov|cc|biz|info|cn|tv)

                          (?:\.cn|\.hk)?

                          )

                    }xms) {

                        print "$1\n";

                }

上面的第一个if专门用来匹配类似jzol.com.cn这种url的域名
用于测试域名:
http://e.baidu.com http://www.etnet.com.cn http://www.ynet.com http://www.zol.com.cn  http://www.isoshu.com  http://www.online.sh.cn/  http://www.forex.com.cn/  http://www.17you.com/  http://www.boosj.com/  http://abcde.com http://jzol.com.cn
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Hadoop perl