第二十七章 Introduction to Perl Programming(中文版)
来源:互联网 发布:耳根算是网络写手吗? 编辑:程序博客网 时间:2024/05/16 01:46
Perl基础
脚本
Perl 是一种脚本语言,它在每次运行前都需要编译。在unix/linux下,通常perl脚本都是以 #!/usr/bin/perl 为开头的。这其实是perl(可执行文件)的全局路径,这个路径当然可以写成其他,只要能找到perl, 但有一点需要注意,perl的全局路径(/usr/bin/perl)不能超过32个字符。Perl的内容和命令行
Perl路径给出后: #!/usr/bin/perl 接下来就该写perl脚本实际 内容了,你可以什么都不写,也可以写点注释语句,当然最应该写的就是命令行了。通常,注释行都是 以"#" 开头的,内容任意,反正在perl脚本中不会被运行。命 令行是以非空格字符开始并且以";"结束的。所以,你可以在把一条命令 写成多行,而直到你给出分号时结束。直接命令行和子程序(函数)
普通命令行在perl脚本中是由上及下一行一行执行的。然而,子程序可以放到任何地方,只有被调用时才会被执行 。子程序是什么样子的呢?如果你看到一段代码以"sub"开头,并且格式是这样的:sub name {command;} , 那 么这就是子程序了。其他特殊行
Perl 可以包含其他程序的代码,但需要这样的格式:require something 或者 use something.引用
单引号: '' 或者: q//双引号: "" 或者: qq//
引用执行结果:`` 或者: qx//
引用几个词组: ('term1','term2','term3') 或者: qw/term1 term2 term3/
引用一个被引用的字符串: qq/"$name" is $name/;
引用包含 "/": qq!/usr/bin/$file is readdy!;
标量上下文和列表上下文
在Perl中,标量上下文和列表上下文是有区别的,这是Perl脚本语言的一个亮点,这个特性在众多脚本语言当中是 独一无二的,也是非常实用的。在Perl的子程序中,不仅可以返回一个列表类似于C中的标量,而且还可以返回一个数组,这个数组不仅可 以给出标量上下文中元素的个数还可以给出列表上下文中元素本身。
Perl该特性的巨大价值应该是显而易见的。
变量和运算符
概况
Perl的变量包含很多内容:标量变量、一维数组、二维数组以及关联数组。你可以通过特殊字符来声明Perl的变量 是标量还是数组,如$variable 表示普通的标量变量; @variable 表示数组;%variable 表示关联数组。 在Perl中,你不需要去区分变量中的字符串和数字,因为Perl可以自动识别它们。标量
赋值变量: $price = 300; $name = "JOHN"; 变量的计算: $price *= 2; $price = $oldprice * 4; $count++; $worth--; 输出变量的值: print $price,"\n";数组
赋值数组: $arr[0] = "Fred"; $arr[1] = "John"; 输出数组: print join(' ',@arr),"\n";二维数组: $arr[0][0] = 5; $arr[0][1] = 7;
哈希(关联数组)
赋值单一元素的哈希: $hash{'fred'} = "USA"; $hash{'john'} = "CANADA";赋值完整哈希:
%a = ( 'r1', 'this is val of r1', 'r2', 'this is val of r2', 'r3', 'this is val of r3',);
或者:%a = ( r1 => 'this is val of r1', r2 => 'this is val of r2', r3 => 'this is val of r3',);
赋值
"="可以把一个值赋给一个变量,或者其他和 "="组合的操作符在赋值的同时也可以做其他操作。$var = "string"; 把string赋予$var
$var = 5; 把数字赋值给$var
$var .= "string"; $var 后面加string
$var += 5;$var加5
$var *= 5; $var乘以5
$var ||= 5; 如果 $var 为 0 则$var的值为 5
$var x= 3; 使$var重复3次,如 $var 原来为a,则现在 为 aaa
替换和赋值:
($new = $old) =~ s/pattern/replacement/;
比较
字符串的比较: eq ne 如 in: $name eq "mary".数字的比较: == != >= <= <=> 如: $price == 400.
And/Or/Not
评估成功或者失败的表达式: $yes or die; 意思是,如果$yes 没有定义那么脚本会 exit. AND 我们可以写成: && 或者 "and" 而OR 我们可以写成: || 或者"or". Not写成 "!"或者 "not".
And, Or 和 Not 一般用于 if() 语句中:
if($first && $second){....;}
if($first || $second){....;}
if($first && ! $second{....;} 这个表示,如果$first 为真,并且$second为假,才会执行{}内的语句。
但大多时候,我们会用unless()语句去替代Not,这样看起来更容易懂:
print if ! $noway; one uses: print unless $noway;
.
分支
if
if(condition){ command;}elsif(condition){ command;}else{ command;}如果满足 condition, 那么会执行 command;
unless (和if相反)
unless(condition){ command1;}else{ command2;}只有满足了condition才会执行command2, 否则执行command1;
循环
while
while(condition){ command;}# 这里的next if表示,当condition2为假时,才会执行command2 while(condition1){ command1; next if condition2; command2;}# 当满足last condition时会退出循环while(condition){ command; last if condition;}# 如果满足condition1 则会执行command1, 同时满足condition2时会进一步执行command2,每执行一次while循环都会执行command3while(condition1){ command1; continue if condition2; command2;}continue{ command3;}# 当满足condition1时,执行command,当同时满足condition1以及condition2时,再次执行commandwhile(condtion1){ command; redo if condition2;}command while condition;
until (和while正好想反)
until(condition){ command;}until(condition){ command; next if condition; command;}until(condition){ command; last if condition;}until(condition){ command; continue if condition; command;}continue{ command;}command until condtion;
for (=foreach)
# 迭代@data,输出每个 $_的值for(@data){ print $_,"\n";}# 把@data的值赋予$infofor $info (@data){ print $info,"\n";}#输出1到100中的奇数for $num (1..100){ next if $num % 2; print $num,"\n";}# (;;),表示为真。当$num>100时就停止循环for (;;){ $num++; last if $num > 100;}
map
# 语法map (command,list);map {comm1;comm2;comm3;} list;
# 例map (rename($_,lc($_),<*>);
.
文件检测操作
正则表达式
什么是正则表达式
正则表达式是用某种模式去匹配字符串的一个公式。通常情况下,你可以通过搜索模式来找到匹配的字符串,也可 以把匹配的字符串给替换为你想要的。模式
Perl的模式很多,可以是一个或多个字符,也可以是某个或者多个特殊字符,当然还可以是任意字符或者无任何字 符。总之,Perl的模式匹配是非常精准、抽象以及灵活的。模式匹配.任意一个字符.*任意个(包含0)任意字符a*the maximum of consecutive a'sa*?the minimum of consecutive a's.?一个或者无任意字符.+一个或者多个任意字符.{3,7}3到7个任意字符,尽量多.{3,7}?3到7个任意字符,尽量少.{3,}至少3个任意字符.{3}3次任意字符[ab]a或者b[^ab]不是a并且也不是b[a-z]任意一个小写字母^a\Aaa开头a$
a\Za结尾A|bb|CCCa或者bb或者CCCtele(f|ph)onetelefone 或者 telephone\w大小写字母或下划线_\W除大小写字母和下划线的任意字符\d0-9 任意一个数字\D除数字之外的所有字符\s空格或者tab、换行以及其他空白字符\S除上面的以外\ttab\n换行\rcarridge return (翻译不通)\b以英文字母,数字为边界的字符串\bkeymatches key but not housekey(?#.......)注释(?i)区分大小写,可以是内部模式变量(?:a|b|c)a 或者 b 或者 c, 但在$n 中不存在字符(?=.....)包含..... 但不会存储在$&(?!.....)不包含..... 但不会存储在$&
替换
你可以使用这样的语句 s/pattern/replacement/把匹配到的 东西给替换。注释:这里的"s"表示命令,然后紧跟着三个分隔符(斜杠),前两个斜杠中的内容就是要匹配的内容,后两个斜 杠中的内容则为要替换为的内容。
可以这样更换一个变量的内容: $var =~ s/pattern/replacement/;
修改一个变量的内容,并把修改后的变量赋值给另外一个变量:
($name = $line) =~ s/^(\w+).*$/$1/;
输入输出
输出一个变量的值
print $var,"\n";输出格式化的字符串
printf("%-20s%10d",$user,$wage);把输入的值赋值给变量,并删除新行
chomp()(perl5)会删除\n以及后面的所有内容。chop()(perl4)会删除最后一个字符,而不管这个字符是什么.chomp($var = <STDIN>);
流线性读入一个文件
open(IN,"<filename") || die "Cannot open filename for input\n";while(<IN>){ command;}close IN;
把读入的文件赋值给数组
open(AAA,"<infile") || die "Cannot open infile\n";@bigarray = <AAA>;close AAA;
把输出的结果重定向到文件中
open(OUT,">file") || die "Cannot oben file for output\n";while(condition){ print OUT $mystuff;}close OUT;
检测打开文件是否会输出信息(eof)
open(IN,"<file") || die "Cannot open file\n";if(eof(IN)){ print "File is empty\n";}else{ while(<IN>){ print; }}close IN;
命令行中提及程序的名字
while(<>){ $file = $ARGV; print $file,"\t",$_; open(IN,"<$file") or warn "Cannot open $file\n"; ....commands for this file.... close(IN);}
得到文件名
得知当前目录
@dir = <*>;
迭代性的使用当前目录
while(<*>){ ...commands...}
通过< >选择文件
@files = </longpath/*.c>;
通过glob()选择文件
This is the official way of globbing:@files = glob("$mypatch/*$suffix");
Readdir()
Perl即使不使用globbing shell也是可以得到目录的,并且既快速又可控,但是我们必须要使用opendir()以及 closedir().opendir(DIR,".") or die "Cannot open dir.\n";while(readdir DIR){ rename $_,lc($_); }closedir(DIR);
Unix命令的输入、输出的重定向
通过Unix管道得到程序要使用的数据
open(IN,"unixcommand|") || die "Could not execute unixcommand\n";while(<IN>){ command;}close IN;
把输出的数据给Unix管道
open(OUT,"|more") || die "Could not open the pipe to more\n";for $name (@names){ $length = length($name); print OUT "The name $name consists of $lenght characters\n";}close OUT;
执行Unix命令
如果输出信息只有一行字符串
system("someprog -auexe -fv $filename");执行Unix命令,并且把输出值赋给变量
如果输出信息只有一行字符串:chomp($date = qx!/usr/bin/date!); The chomp($date = qx!/usr/bin/date!); chomp()(perl5)把字符串后边的换行符“\n”去掉,$date得到Unix命令 "date"的值.
如果输出信息是多行,那么Perl会把所有输出信息存到数组中:
chomp(@alllines = qx!/usr/bin/who!);
替换整个Perl程序为一个Unix程序
exec anotherprog; 但是这样会删除掉Perl程序Perl内置函数
字符串函数
所有小写变大小: $name = uc($name);只把第一个字母变大写: $name = ucfirst($name);所有大写变小写: $name = lc($name);只把第一个字母变小写: $name = lcfirst($name);得到字符串的长度:$size = length($string);截取字符串的第4到第5:$part = substr($whole,4,5);删除行尾(一般是删除换行符以及下面内容):chomp($var);删除最后一个字符:chop($var);拷贝(把$word的值拷贝给$salt):$code = crypt($word,$salt);把字符串当作perl代码来执行:eval $var;打印字符(substring)在字符串(string)的什么位置:$pos = index($string,$substring);最后面的substring在string的什么位置:$pos = rindex($string,$substring);引用字符串:$quote = quotemeta($string);数组函数
和Unix中的grep类似,过滤出符合要求的元素:@found = grep(/[Jj]ohn/,@users);把数组各元素作为操作对象,本例中把每个元素所有字母都变为大写:@new = map(lc($_),@start);把数组中的所有元素组合成一个字符串,元素间用函数给定的分隔符分割,本例中分隔符为空格:$string = join(' ',@arr);把一个字符串分割成一个数组:@data = split(/&/,$ENV{'QUERY_STRING'};按字母顺序排序数组:sort(@salery);将数组的次序颠倒:reverse(@salery);获取哈希的键:keys(%hash);获取哈希的值:values(%hash);获取哈希的键和值:each(%hash);清空数组:@arr = ();删除哈希中的某个元素:delete $hash{$key};检查哈希的某个键是否存在:if(exists $hash{$key}){;}查看哈希是否有元素:scalar %hash;把数组最后一个元素取出来并返回其值:$last = pop(@IQ_list);把数组第一个元素取出来并返回其值:$first = shift(@topguy);在数组最后增加一个元素:push(@waiting,$name);在数组最前面增加一个元素:unshift(@nowait,$name);把数组从第0个元素起,共2个元素替换为$var,这里的0和2不是固定的:splice(@arr,0,2,$var);得到数组总共有多少个元素:scalar @arr;得到数组最后一个索引:$lastindex = $#arr;操作文件的函数
打开文件作为输入内容:open(IN,"</path/file") || die "Cannot open file\n";打开文件作为输出内容:open(OUT,">/path/file") || die "Cannot open file\n";打开文件作为追加内容:open(OUT,">>$file") || &myerr("Couldn't open $file");关闭文件:close OUT;给文件设置权限:chmod 0755, $file;删除文件:unlink $file;给文件重命名:rename $file, $newname;给文件做硬链接:link $existing_file, $link_name;给文件做软链接:symlink $existing_file, $link_name;创建目录:mkdir $dirname, 0755;删除目录:rmdir $dirname;把$file的大小减小到$size:truncate $file, $size;修改文件的所属主以及所属组:chown $uid, $gid;找到软链接文件的源文件:$file = readlink $linkfile;获取文件的全部属性信息:@stat = stat $file;转换函数
数字变字符:chr $num;字符变数字:ord($char);十六进制变浮点:hex(0x4F);八进制变浮点:oct(0700);把time变成本地时间格式:localtime(time);把time变成格林威治格式:gmtime(time);把一个列表或数组以在实际机器存贮格式或C等编程语言使用的格式转化到一个简单变量中:$string = pack("C4",split(/\./,$IP));与pack功能相反,将以机器格式存贮的值转化成Perl中值的列表:@arr = unpack("C4",$string);子程序(等同于C语言中的函数)
定义一个子程序
sub mysub { command;}
例子:sub myerr { print "The following error occured:\n"; print $_[0],"\n"; &cleanup; exit(1);}
调用一个子程序
&mysub;
给子程序参数
&mysub(@data);
在子程式中接收参数
作为全局变量:sub mysub { @myarr = @_;}
sub mysub { ($dat1,$dat2,$dat3) = @_;}
作为局部变量:sub mysub { local($dat1,$dat2,$dat3) = @_;}
一些特殊的变量
语法
含义
$_在(@arr){ $field = $_ . " ok"; } 这个例子中,$_表示循环中的字符串$.表示当前程序的行号: while(){$0程序名$$运行该perl脚本的进程号$<当前程序的真实uid$>当前程序有效的uid$|该变量默认为0,当设定为非0时,会强制刷新输出: select XXX; $| = 1;$&最后一次匹配模式匹配到的字符串$1....The ()-embraced matches of the last patternsearch$`含有上次成功的模式匹配内容之前的字符串$'含有上次成功的模式匹配内容之后的字符串派生
if($pid = fork){ # 父 command;}elsif($pid == 0){ # 子 command; # 子必须以exit为结尾!! exit;}else{ # 错误 die "Fork did not work\n";}
为派生的子创建管道
创建一个管道
pipe(READHANDLE,WRITEHANDLE);
刷新管道
select(WRITEHANDLE); $| = 1; select(STDOUT);
在父与子之间设置两个管道
pipe(FROMCHILD,TOCHILD); select(TOCHILD); $| = 1; select(STDOUT);pipe(FROMPARENT,TOPARENT);select(TOPARENT);$| = 1; select(STDOUT);if($pid = fork){ # 父 close FROMPARENT; close TOPARENT; command;}elsif($pid == 0){ # 子 close FROMCHILD; close TOCHILD; command; exit;}else{ # 错误 command; exit;}
创建一个套接字来连接另外的计算机
# 需要放置在脚本开始的一些地方require 5.002;use Socket;use sigtrap;# 需要提前设置好的一些信息$port = 80;$remote = 'remotehost.domain';$iaddr = inet_aton($remote);$paddr = sockaddr_in($port,$iaddr);# 套接字socket(S,AF_INET,SOCK_STREAM,$proto) or die $!;# 刷新套接字select(S); $| = 1; select(STDOUT);# 连接connect(S,$paddr) or die $!;# 输入到套接字print S "something\n";# 从套接字中读取$gotit = <S>;#只读出一个字符read(S,$char,1);# 关闭套接字close(S);
获取Unix用户以及网络相关信息
或者通过指定uid的方式获取用户的密码: @entry = getpwuid ("$UID");
你也可以得到group, host, network, services, protocols这些信息通过以下命令: getgrnam, getgrid, gethostbyname, gethostbyaddr, getnetbyname, getnetbyaddr, getservbyname, getservbyport, getprotobyname, getprotobynumber.
你还可以通过如下方式,获取一系列你想得到的信息,只不过你需要一个循环而已:
setpwent;
while(@he = getpwent){
commands...
}
entpwent;
如,你想要得到一些用户的家目录:
setpwent;while(@he = getpwent){ printf("%-20s%-30s\n",$he[0],$he[7]);}endpwent;
类似的,该方法同样适用于上面刚刚描述的那些东西,只不过需要在设置命令后面加上一个"stayopen" .数学计算
减: -
乘: *
除:/
平方:**
返回e的n次方,()内为n exp()
模:%
平方根: sqrt()
绝对值: abs()
Tangens: atan2()
Sinus: sin()
Cosine: cos()
返回一个随机数: rand()
使用“format”格式化输出
format filehandle =
@<<<<<<<<<<@###.#####@>>>>>>>>>>@||||||||||
$var1, $var3, $var4
.
现在可以使用上面定义的输出格式了:
write FILEHANDLE;
The @<<< does left adjustment, the @>>> right adjustment, @##.## is for numericals and @||| centers.
命令行下使用Perl
- 第二十七章 Introduction to Perl Programming(中文版)
- Udacity cs344-Introduction to Parallel Programming学习笔记-第二单元
- Introduction to ANTLR 中文版
- Introduction to MMX Programming
- Introduction to Java Programming
- Introduction to Windows Programming
- Introduction to SSE Programming
- Introduction to RDMA programming
- Introduction to Reliable Distributed Programming
- Introduction to programming with OpenCV
- Introduction To Unix Signals Programming
- Introduction to Oracle SALT Programming
- An Introduction to Bluetooth Programming
- Introduction to programming with OpenCV
- Introduction to programming with OpenCV
- Introduction to programming with OpenCV
- An Introduction to OpenCL Programming
- Introduction to DirectShow Application Programming
- 裹在刘翔奥运失利事件上的十六层谜云
- HDU P1011(TreeDP)
- Steve Pavlina的睡眠日志
- Fedora自动登录root用户
- 毕业了,然后呢?!那些繁华如梦的似水流年和魂牵梦绕的若即若离~~~
- 第二十七章 Introduction to Perl Programming(中文版)
- 跟踪上传进度PHP和JavaScript
- Node(25) sharing code between client and server
- 通过配置ant提高EJB开发效率
- 无法执行添加/移除操作,因为代码元素CxxxDlg.cpp是只读的
- Symbol not found: _objc_storeStrong
- 效率
- Uedit32比较2个文件的内容
- Android ViewPager放入多个XML。如何监听其的控件?