当前位置: 首页 > 工具软件 > Perl > 使用案例 >

perl 脚本

池宸
2023-12-01

perl语言

1. 基本语法

perl 语言是用于文本处理语言,它代表实用提取和报告语言,可在各种平台运行(windows unix等)

1.环境搭建与使用

安装perl 软件

perl -v # 检查版本信息

从官网下载perl 软件后,直接将程序添加到环境变量即可。

注意事项(链接:https://www.perl.org/get.html):

Perl 在 Window 平台上有 ActiveStatePerl 和 Strawberry Perl 编译器。

ActiveState Perl和 Strawberry Perl最大的区别是 Strawberry Perl 里面有多包含一些 CPAN 里的模块, 所以Strawberry Perl 下载的安装文件有 80多M, 而ActiveState Perl 只有20M 左右。

我们这里使用了 Strawberry Perl 。

windows 安装 perl 后,可以直接实用 Perl + perl 脚本运行(以pl 为文件后缀)
比如:打印 hello world

# print 打印函数
print "Hello, world\n";

perl 脚本注释

#注释一 #
#注释二 =cut  ***  =cut

=cut  #begin comment
This is all part of multiline comment.
You can use as many lines as you like
These comments will be ignored by the 
compiler until the next =cut is encountered.
=cut

2. 语法

1. perl 中空格 单引号 双引号处理
空格: 不做处理
单引号:单引号不插入任何变量或特殊字符
双引号: 双引号插入变量和特殊字符(例如换行符\n)

测试用例

# 注释
print "hello world\n";

$str1 = "str1 hello world\n";
$str2 = 'str2 hello world\n';

print "$str1 $str2\n";
print '$str1 $str2\n';

running:
hello world
str1 hello world
 str2 hello world\n
$str1 $str2\n

perl 中转义字符

\"  \r \n 等 会影响print 的输出

perl 标识符

Perl标识符是用于标识变量,函数,类,模块或其他对象的名称。Perl变量名称以$,@或%开头,后跟零个或多个字母,下划线和数字(0至9)。
Perl不允许在标识符内使用标点符号,例如@,$和%。Perl是区分大小写的编程语言。
1. perl 数据类型

标量 数组 哈希

  • 标量 - 标量是简单的变量。它们前面有一个美元符号($)。标量可以是数字,字符串或引用。引用实际上是变量的地址,我们将在接下来的章节中看到它。
  • 数组 - 数组是用数字索引访问的标量的有序列表,数字索引以0开头。它们的前面是“ at”符号(@)。
  • 哈希 - 哈希是使用键作为下标访问的键/值对的无序集合。它们前面有一个百分号(%)。

变量修饰符
1)my 作用:把变量的名字和值都限于某个范围内,也就是说,该变量只能本层模块或者函数
可以看到这个变量,高一层或者低一层的都看不到。
2)our 作用:把变量名字限于某个范围,其实就是明确声明一个”全局变量”,虽然是在某个
模块或者函数里面定义,外面的也可以访问,如果已经声明过了,再次用our,表示此处用的和之前声明的our变量
是同一个。
3)local 作用:把值局限于某个范围,该范围与my有所区别的是,包含本层及本层的下层,
但本层的上一层不可以访问。

测试用例

# 变量 以$开头的
$test = "this is a value";

# 数组 以@开头的
@day = ("Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday");

# 哈希 以%开头的
%table = ("xiaoming",25,"xiaohong",28,"xiaoli",24);

print "$test\n";

print "@day[0] @day[1] @day[2] @day[3] @day[4] @day[5]\n";

print "xiaoming: @table{xiaoming} xiaohong: @table{xiaohong} xiaoli: @table{xiaoli}\n";

rinning:
this is a value
Monday Tuesday Wednesday Thursday Friday Saturday
xiaoming: 25 xiaohong: 28 xiaoli: 24

序号数组:Perl提供了用于连续数字和字母的快捷方式

数组大小:

@day = ("Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday");

$size = @day;
$max_ind = $#day;

print "$size \n";
print "$max_ind \n" 

数组元素添加与删除,函数操作

函数类型描述
pushpush @ARRAY, LIST将列表的值压入数组的末尾。(尾增)
poppop @ARRAY弹出并返回数组的最后一个值。(尾删)
shiftshift @ARRAY将数组的第一个值移开并返回,将数组缩短1并向下移动所有内容。(头删)
unshiftunshift @ARRAY, LIST将列表添加到数组的最前面,并返回新数组中的元素数。(头增)
splicesplice @ARRAY, OFFSET [ , LENGTH [ , LIST ] ]更换数组中元素 偏移 长度 更换值
splitsplit [ PATTERN [ , EXPR [ , LIMIT ] ] ]字符串拆分数组
joinjoin EXPR, LIST数组变成字符串
sortsort [ SUBROUTINE ] LIST数组排序

哈希定义(键和值):

%data = ('John Paul' => 45, 'Lisa' => 30, 'Kumar' => 40);

获取键(keys)和值(values)的函数
测试用例

@test = (1..10);
print "@test\n";

%table = ("xiaoming",25,"xiaohong",28,"xiaoli",24);
#相同含义
#%table = ('xiaoming',25,'xiaohong',28,'xiaoli',24);
#%table = ('xiaoming'=>25,'xiaohong'=>28,'xiaoli'=>24);
print "@table{xiaoming} @table{xiaohong} @table{xiaoli}\n";

@test_key = keys %table;
@test_value = values %table;
print "@test_key  @test_value";

running:
1 2 3 4 5 6 7 8 9 10
25 28 24
xiaoli xiaohong xiaoming  24 28 25

哈希需要计算大小,需要获取出其keys 或者values 变成数组,计算其大小

哈希的添加删除

# 哈希添加删除
%data = ('John Paul' => 45, 'Lisa' => 30, 'Kumar' => 40);
@keys = keys %data;
$size = @keys;
print "1 - Hash size:  is $size\n";

# adding an element to the hash;
$data{'Ali'} = 55;
@keys = keys %data;
$size = @keys;
print "2 - Hash size:  is $size\n";

# delete the same element from the hash;
delete $data{'Ali'};
@keys = keys %data;
$size = @keys;
print "3 - Hash size:  is $size\n";
2. 条件语句

++if语句++

if(boolean_expression) {
   # statement(s) will execute if the given condition is true
}

#例如
if(boolean_expression 1) {
   # Executes when the boolean expression 1 is true
} elsif( boolean_expression 2) {
   # Executes when the boolean expression 2 is true
} elsif( boolean_expression 3) {
   # Executes when the boolean expression 3 is true
} else {
   # Executes when the none of the above condition is true
}

++unless语句++

unless(boolean_expression 1) {
   # Executes when the boolean expression 1 is false
} elsif( boolean_expression 2) {
   # Executes when the boolean expression 2 is true
} elsif( boolean_expression 3) {
   # Executes when the boolean expression 3 is true
} else {
   # Executes when the none of the above condition is met
}

++switch语句++

use Switch;

switch(argument) {
   case 1            { print "number 1" }
   case "a"          { print "string a" }
   case [1..10,42]   { print "number in list" }
   case (\@array)    { print "number in list" }
   case /\w+/        { print "pattern" }
   case qr/\w+/      { print "pattern" }
   case (\%hash)     { print "entry in hash" }
   case (\&sub)      { print "arg to subroutine" }
   else              { print "previous case not true" }
}

三目运算符 ? : 与c语言一致

++while++ 循环

while(condition) {
   statement(s);
}

do {
   statement(s);
}while( condition );

**++for循环语句++
**

for ( init; condition; increment ) {
   statement(s);
}

无限循环

for( ; ; ) {
   printf "这里将永远执行.\n";
}

while( true ) {
  printf("这里将永远执行.\n");
}
循环类型描述
while循环在给定条件为真时重复一个语句或一组语句。它在执行循环体之前测试条件
until循环重复一个语句或一组语句,直到给定条件变为真为止。它在执行循环体之前测试条件。
for循环多次执行一系列语句,并简化管理循环变量的代码。
foreach 循环foreach循环遍历常规列表值,并将变量var 依次设置为列表的每个元素。
do… while循环它更像while语句,除了它在循环主体的末尾测试条件(do…while循环至少会执行一次)。
嵌套循环您可以在任何其他while,for或do…while循环内使用一个或多个循环

测试用例

$tmp = 30;
@pl_value = (15..35);
#for($index=15;$index<35;$index=$index+1)
for( $index = 10; $index < 20; $index++ )
{
	if(@pl_value[$index] >= 30)
	{
			#print "the value is @pl_value[$index]\n";
		use Switch;
		
	    switch(@pl_value[$index])
	    {
	    case 30    {print "the value is @pl_value[$index]\n"}
		
		case 31    {print "the value is @pl_value[$index]\n"}
		
		case 32    {print "the value is @pl_value[$index]\n"}
		
		case 33    {print "the value is @pl_value[$index]\n"}
		
		case 34    {print "the value is @pl_value[$index]\n"}
		
		case 35    {print "the value is @pl_value[$index]\n"}
		
		else       {print "the value is null"}
    	}
	}
}

runningL:
the value is 30
the value is 31
the value is 32
the value is 33
the value is 34


#foreach 测试
@list = (2, 20, 30, 40, 50);

# foreach loop execution
foreach $a (@list) {
   print "value of a: $a\n";
}

rinning:
value of a: 2
value of a: 20
value of a: 30
value of a: 40
value of a: 50

++循环使用关键字++
next continue last goto

2. 运算符

perl 支持的运算符如下

  • 算术运算符
操作符描述例子
+加两个操作数。$a + $b将得到30
-从第一个减去第二个操作数。 a − a- ab将得到-10
*将两个操作数相乘。$a * $b将给出200
/将分子除以除分母。$b / $a将给出2
模运算符和整数除法后的余数。$b % $a将给出0
**对运算符执行指数(幂)计算$a ** $b将得到10的20次方
  • 关系运算符
操作符描述例子
==检查两个操作数的值是否相等。如果是,则条件变为真。($a == $b)为false。
!=检查两个操作数的值是否相等。如果值不相等,则条件为真。($a != $b)为true。
<=>检查两个操作数的值是否相等,并根据左参数在数值上小于,等于或大于右参数而返回-1、0或1。($a <=> $b)为 -1。
>检查左操作数的值是否大于右操作数的值。如果是,则条件变为真。($a > $b) 为false。
<检查左操作数的值是否小于右操作数的值。如果是,则条件变为真。($a < $b)为true。
>=检查左操作数的值是否大于或等于右操作数的值。如果是,则条件变为真。($a > = $b)为false。
<=检查左操作数的值是否小于或等于右操作数的值。如果是,则条件变为真。($a <= $b)为true。
  • 字符串运算符
操作符描述例子
lt如果left参数在字符串上小于right参数,则返回true。($a lt $b) 为 true.
gt如果left参数在字符串上大于right参数,则返回true。($a gt $b) 为 false.
le如果left参数在字符串上小于或等于right参数,则返回true。($a le $b) 为 true.
ge如果left参数在字符串上大于或等于right参数,则返回true。($a ge $b) 为 false.
eq如果left参数在字符串上等于right参数,则返回true。($a eq $b) 为 false.
ne如果left参数沿字符串方向不等于right参数,则返回true。($a ne $b) 为 true.
cmp返回-1、0或1,具体取决于左参数是按字符串方式小于,等于还是大于右参数。($a cmp $b) 为 -1.
  • 赋值运算符
操作符描述例子
=简单的赋值运算符。将值从右侧操作数分配给左侧操作数$c = $a+ b 将 b将 ba + b 的 值 赋 给 b的值赋给 bc
+=加和赋值运算符。它将右操作数添加到左操作数,并将结果分配给左操作数。$c + = a 等 于 a等于 ac = $c + $a
-=减和赋值运算符。它从左侧操作数中减去右侧操作数,并将结果分配给左侧操作数。$c-= a 等 效 于 a等效于 ac = c − c- ca
*=乘以和赋值运算符。它将右操作数与左操作数相乘,并将结果分配给左操作数。$c * = a 等 效 于 a等效于 ac = $c * $a
/=除和赋值运算符。它将左操作数除以右操作数,并将结果分配给左操作数。$c / = a 等 于 a等于 ac = $c / $a
%=模和赋值运算符。它使用两个操作数取模,然后将结果分配给左操作数。$c%= a 等 于 a等于 ac = c % c% ca
**=指数和赋值运算符,对运算符执行指数(幂)计算并将值赋给左操作数c = $ a等效于$c = $c $a
  • 按位运算符
&,|和^
  • 逻辑运算符
    && and || or not !
操作符描述例子
and称为逻辑AND运算符。如果两个操作数都为真,则条件为真。($a and $b)为false。
&&称为逻辑与运算符。如果两个操作数都不为零,则条件变为true。($a && $b)为false。
or称为逻辑或运算符。如果两个操作数中的任何一个都不为零,则条件为真。($a or $b)为true。
not称为逻辑非运算符。用于反转其操作数的逻辑状态。如果条件为真,则逻辑非运算符将为假。!($a && $b)为false。
  • 类引用运算符
操作符描述例子
q {}用单引号将字符串引起来q {abcd} 得 ‘abcd’
qq {}用双引号将字符串引起来qq {abcd} 得 “abcd”
qx {}用反引号引起来的字符串qx {abcd} 得 abcd
  • 杂项运算符
操作符描述例子
.二进制运算符点(.)连接两个字符串如果 a = “ a b c ” , a=“abc”, a=abcb =“def”,则 a . a. a.b将 得到 “abcdef”
x重复运算符x返回由左操作数组成的字符串,该字符串重复了右操作数指定的次数。(‘-’ x 3)将得到 —。
范围运算符…返回从左值到右值计数(逐个递增)的值列表(2…5)将得到(2,3,4,5)
++自动增量运算符将整数值增加一$a++将给出11
自动减量运算符将整数值减一$a–将给出9
->箭头运算符主要用于从对象或类名中解引用方法或变量 o b j − > obj-> obj>a是从对象 o b j 访 问 变 量 obj访问变量 obj访a的示例。
3. 时间相关

相关函数
函数一:
localtime() #系统时间

#time相关函数
$time = localtime();
print "$time\n";

#output
Tue May 10 11:43:30 2022

函数二:
gmtime() #utc时间 不带tz

$time1 = gmtime();
print "$time1 \n";

#output
Tue May 10 03:49:08 2022

函数三:
time() #1970年到现在的秒数

$time2 = time();  
print "$time2 \n";

#output
1652154548

函数四:
sleep

$time = localtime();   
print "$time\n";

$time1 = gmtime();
print "$time1 \n";

$time2 = time();       #1970年到现在的秒数
print "$time2 \n";

sleep 5;

$time4 = localtime();
print "$time4 \n";
$time3 = localtime($time2);  #1970 s转换成时间
print "$time3 \n";

函数五:
strftime() #格式化输出时间

use POSIX qw(strftime); 
print strftime("%Y-%m-%d %H:%M:%S\n", localtime(time)); 

#Output
2022-05-10 13:18:40
4. 函数

函数定义
sub subroutine_name {
body of the subroutine
}

传参:@_ 接收

return 返回值

test 一:
函数定义与传参,返回值

#function
sub test_add
{
	
print "this is a function @_[0] @_[1] @_[2] \n";

return @_[0]+@_[1]+@_[2]
}


$ret = test_add(10,20,30);
print "this value is $ret \n";

test 二:
数组传参

#function  数组传参
sub test_add
{
$test_size = @_;
$add_value = 0;
print "this is a function $test_size \n";
while($test_size >= 0)
{
	
	$add_value = $add_value + @_[$test_size];
	$test_size --;
	print "this value is $add_value \n";
}

return $add_value;
#return @_[0]+@_[1]+@_[2]
}

@test = (10..15);

$ret = test_add(@test);
print "this value is $ret \n";

test 三:
哈希传参

#function  哈希传参
sub test_add
{
$test_size = @_;
$add_value = 0;
print "this is a function $test_size \n";
while($test_size >= 0)
{
	
	print "[test_add]this value is @_[$test_size-1] \n";
		$test_size --;
}

%table = @_;
@test_key = keys %table;
@test_value = values %table;
print "@test_key   @test_value \n";

return 0;
}

@test = ("xiaoming",25,"xiaohong",28,"xiaoli",24);

$ret = test_add(@test);
print "this value is $ret \n";
5. perl io操作

open 操作

print 写入文件

# Open file 
open(DATA1, "+>file1.txt");
#write file1 
print DATA1 "/*-------------------------------------------------------------\n";
print DATA1 "**  file name: quectel_test.c\n";
print DATA1 "**  function: feature control\n";
print DATA1 "**  create date: localtime()\n";
print DATA1 "*-------------------------------------------------------------*/\n";
print DATA1 "#define QUECTEL_TEST1\n";
print DATA1 "#define QUECTEL_TEST2\n";
print DATA1 "#define QUECTEL_TEST3\n";

# Open new file to write
open(DATA2, ">file2.txt");

# Copy data from one file to another.
while(<DATA1>) {
   print DATA2 $_;
}
close( DATA1 );
close( DATA2 );
实体定义
<或r只读访问
>或w创建,写入和截断
>>或>编写,附加和创建
+<或r+读写
+>或w+读取,写入,创建和截断
+>>或a+读取,写入,附加和创建

getc 函数
getc 函数从指定的FILEHANDLE中返回单个字符,如果未指定则返回STDIN-

read 函数
read 函数从缓冲的文件句柄中读取信息块:此函数用于从文件中读取二进制数据。

6. perl 错误处理

warn 函数
warn 函数仅会发出警告,一条消息会打印到STDERR,但不会采取进一步措施。因此,如果您只想为用户打印警告并继续进行其余操作,它会更有用-

die 函数
die 函数的作用与 warn 相似,只是它还会调用 exit。在普通脚本中,此函数具有立即终止执行的作用。如果程序中有错误,则应使用此功能以防继续进行-

2. perl 操作不同格式文件

excel 环境需要安装WriteExcel 插件(暂时先不搞了 环境一直有问题)
注意事项:安装cpanm 安装模块

1.安装perl

2.dmake: 
http://mirrors.163.com/cpan/authors/id/S/SH/SHAY/dmake-4.12.2.2.zip

3.cpanm(App::cpanminus):
http://mirrors.163.com/cpan/authors/id/M/MI/MIYAGAWA/App-cpanminus-1.7040.tar.gz

4. 安装perl并添加环境变量(exe文件里面有提示添加,可以在那里添加即可,假设Perl安装路径是D:\Perl64)。


3. 将dmake-4.12.2.2.zip解压,把 startup 文件夹和 dmake.exe 文件放入D:\Perl64\bin


4. 解压App-cpanminus-1.7040.tar.gz 到任意目录,cmd窗口进入,输入如下命令:
perl Makefile.PL

dmake test

dmake install

5.使用cpanm 安装缺少的模块

操作excel(使用OLE模块) 实例

use Win32::OLE qw(in with);
use Win32::OLE::Const 'Microsoft Excel';
 
$AT_LIST_XLS = "test.xlsx";
$sheetname = "at";

my $Excel = Win32::OLE->GetActiveObject('Excel.Application')
    || Win32::OLE->new('Excel.Application', 'Quit');  # get already active Excel
                                                      # application or open new

#新建
#my $Book = $Excel->Workbooks->add;
#my $Sheet = $Book->Worksheets(1);
#打开已经有的
my $Book = $Excel->Workbooks->Open($AT_LIST_XLS);     # open Excel file
my $Sheet = $Book->Worksheets($sheetname);    


$row = 1;
$col = 1;

while(1)
{
    $ret = $Sheet->Cells($row, $col)->{'Value'}; #取值 根据行和列  
	if (length($ret) == 0)   #读到第一列如果为空,不再继续读,退出excel
	 {
		last;
	 }else
	 { 
	     $Sheet->Cells($row, $col+1)->{'Value'} = send_at($ret);  #写值 根据行和列  
	 }
	 $row++;
      
	 #send_at($ret);	 

}

$Book->SaveAs($AT_LIST_XLS);

$Book->Close;

json 安装json模块
xml 安装xml 模块

3. perl 操作设备

注意事项: SerialPort这个模块的使用 需要安装perl Strawberry版本 否则会报错

操作窗口设备 发送at指令

#强制全局变量用my修饰
use  strict;  
#使用串口模块
use  Win32::SerialPort;

#定义串口,并打开它
my $testPORTNAME = "COM13";
my $ob = Win32::SerialPort->new($testPORTNAME) || die "open com failed";

print "open com success\n";

#配置串口设置
eval  {
 $ob -> baudrate( 115200 );    #如果使用超过115200的波特率,执行脚本前先用串口通信工具用对应波特率打开串口,发个AT。

 $ob -> parity( 'none' );
 $ob -> databits( 8 );
 $ob -> stopbits( 1 );
#$ob -> handshake( 'rts' );  #硬件流控
 $ob -> handshake( 'none' );  #无流控
 #$ob->buffers(4096, 4096);
};
if  ($@) { die   ' set $testPORTNAME properties failed ' ;}

$ob -> write_settings ||  die   " CANNOT WRITE $testPORTNAME DRIVER ";

#发送at命令
$ob->write ("ATI\r\n");   #写到串口
sleep(1);

#读取命令返回值
my($count, $string) = $ob->read(100); #从串口读100字节数据,读到的数据长度$count, 数据赋值给$string
if(defined($string))   #读到了数据
{
 print $string;
}

$ob->close;   #关闭串口
undef   $ob ;

exit(0);

测试结果如下:
open com success
ATI
Quectel
EC20F
Revision: EC20CEFARGR06A03M4G_OCPU

OK
 类似资料: