强大的正则表达式
自动化运维脚本
CGI编程语言
BioPerl生态系统
perl [选项] [程序文件] [参数...]
perl [选项] -e 程序代码 [参数...]
perl [选项] - [程序文件] [参数...]
| 选项 | 说明 |
|---|---|
-e 程序代码 |
在命令行中直接执行Perl代码 |
-n |
为输入行隐式添加循环 |
-p |
为输入行隐式添加循环并打印 |
-l |
自动对输入输出进行换行处理 |
-a |
自动分割输入行到@F数组 |
-F分隔符 |
指定-a选项的分隔符 |
-i[扩展名] |
原地编辑文件(可备份) |
-M模块 |
加载Perl模块 |
-w |
启用警告信息 |
-W |
启用所有警告 |
-c |
检查语法而不执行 |
-v |
显示Perl版本信息 |
-V |
显示Perl配置信息 |
-d |
启动调试器 |
-h |
显示帮助信息 |
#!/usr/bin/perl
# 单行注释
print "Hello, World!\n";
# 使用say(需要Perl 5.10+)
use feature 'say';
say "Hello, World!";
# 命令行执行
# perl -e 'print "Hello, World!\n"'
#!/usr/bin/perl
# 标量变量(以$开头)
$name = "Alice";
$age = 25;
$price = 99.99;
$flag = 1; # true
$null = undef;
# 数组(以@开头)
@fruits = ("apple", "banana", "orange");
$first_fruit = $fruits[0]; # 访问数组元素
# 哈希(以%开头)
%person = (
"name" => "Bob",
"age" => 30,
"city" => "New York"
);
$person_name = $person{"name"}; # 访问哈希元素
print "Name: $name\n";
print "Fruits: @fruits\n";
print "Person: $person{'name'}, $person{'age'}\n";
#!/usr/bin/perl
# 条件语句
$score = 85;
if ($score >= 90) {
print "优秀\n";
} elsif ($score >= 60) {
print "及格\n";
} else {
print "不及格\n";
}
# 循环语句
# for循环
for my $i (1..10) {
print "$i ";
}
print "\n";
# while循环
my $count = 0;
while ($count < 5) {
print "Count: $count\n";
$count++;
}
# foreach循环
foreach my $fruit ("apple", "banana", "orange") {
print "Fruit: $fruit\n";
}
# 1. 打印文件内容(相当于cat)
perl -pe '' file.txt
# 2. 给文件每行添加行号(相当于nl)
perl -pe '$_ = "$. $_"' file.txt
# 3. 显示文件的第5-10行(相当于sed -n '5,10p')
perl -ne 'print if 5..10' file.txt
# 4. 统计文件行数(相当于wc -l)
perl -lne 'END { print $. }' file.txt
# 5. 反转文件行顺序(相当于tac)
perl -e 'print reverse <>' file.txt
# 1. 搜索包含"error"的行(相当于grep)
perl -ne 'print if /error/i' logfile.txt
# 2. 搜索并显示行号(相当于grep -n)
perl -ne 'print "$.: $_" if /error/' logfile.txt
# 3. 替换文件中的文本(原地编辑,备份原文件)
perl -i.bak -pe 's/foo/bar/g' file.txt
# 4. 替换多个文件中的文本
perl -i -pe 's/old/new/g' *.txt
# 5. 仅替换匹配的行
perl -i -pe 's/foo/bar/g if /pattern/' file.txt
# 1. 提取IP地址
perl -ne 'print "$1\n" while /(\d+\.\d+\.\d+\.\d+)/g' access.log
# 2. 提取第2列数据(以空格分隔)
perl -lane 'print $F[1]' data.txt
# 3. 提取第2列,按数字排序
perl -lane 'push @nums, $F[1]; END { print for sort {$a <=> $b} @nums }' data.txt
# 4. 计算数值总和
perl -lane '$sum += $F[2]; END { print $sum }' numbers.txt
# 5. 统计单词频率
perl -lne '$count{$_}++ for split; END { print "$_: $count{$_}" for sort keys %count }' text.txt
#!/usr/bin/perl
$text = "Hello, World! Perl is powerful. perl@example.com";
# 匹配
if ($text =~ /Perl/) {
print "找到 Perl\n";
}
# 不区分大小写匹配
if ($text =~ /perl/i) {
print "找到 perl(不区分大小写)\n";
}
# 全局匹配
while ($text =~ /(\w+)/g) {
print "单词: $1\n";
}
# 替换
$text =~ s/World/Perl/;
print "替换后: $text\n";
# 提取电子邮件
if ($text =~ /(\w+@\w+\.\w+)/) {
print "电子邮件: $1\n";
}
| 模式 | 说明 | 示例 |
|---|---|---|
/\w+/ |
匹配单词字符 | hello, world123 |
/\d+/ |
匹配数字 | 123, 456 |
/\s+/ |
匹配空白字符 | 空格, 制表符 |
/^开始/ |
匹配行首 | ^Hello |
/结束$/ |
匹配行尾 | world$ |
/(...)/ |
分组捕获 | /(\d+)-(\d+)/ |
/[abc]/ |
字符集 | a, b或c |
/a|b/ |
或操作 | a或b |
/\bword\b/ |
单词边界 | 独立的word |
# 提取HTML中的链接
perl -ne 'while (/{"name"}' data.json
# 提取CSV的特定列
perl -F, -lane 'print $F[2]' data.csv
#!/usr/bin/perl
# 读取文件
open my $fh, '<', 'input.txt' or die "无法打开文件: $!";
while (my $line = <$fh>) {
chomp $line; # 去除换行符
print "读取: $line\n";
}
close $fh;
# 写入文件
open my $out, '>', 'output.txt' or die "无法创建文件: $!";
print $out "第一行\n";
print $out "第二行\n";
close $out;
# 追加到文件
open my $append, '>>', 'log.txt' or die "无法打开日志文件: $!";
print $append scalar localtime . " 日志条目\n";
close $append;
# 读取整个文件
my $content = do {
local $/ = undef;
open my $fh, '<', 'file.txt' or die $!;
<$fh>;
};
# 1. 批量重命名文件(添加前缀)
perl -e 'for (@ARGV) { rename $_, "prefix_$_" }' *.txt
# 2. 批量修改文件扩展名
perl -e 'for (@ARGV) { /(.*)\.old$/; rename $_, "$1.new" if $1 }' *.old
# 3. 查找并删除空文件
perl -e 'unlink for grep { -f $_ and -z $_ } @ARGV' *
# 4. 批量转换文件编码(GBK转UTF-8)
perl -i -MEncode -pe '$_ = encode("utf-8", decode("gbk", $_))' *.txt
# 5. 文件大小排序
perl -e 'print "$_\n" for sort { -s $b <=> -s $a } @ARGV' *
# 查找并杀死特定进程
perl -e 'kill 9, map { /^\s*(\d+)/ } `ps aux | grep httpd`'
# 监控进程内存使用
perl -ne 'if (/^(\d+)\s+.*?(\d+)\s+(\d+)/) {
print "PID: $1, RSS: $2 KB, VSZ: $3 KB\n" if $2 > 100000
}' <(ps aux)
# 统计进程数量
perl -e 'print scalar `ps aux | wc -l` - 1, " 个进程运行中\n"'
# 查找大文件(大于100MB)
find /home -type f -exec perl -e '
print "$ARGV[0]\n" if -s $ARGV[0] > 100*1024*1024
' {} \;
# 按目录统计磁盘使用
du -sk * | perl -ane 'printf "%8d MB %s\n", $F[0]/1024, $F[1]'
# 监控磁盘使用率
df -h | perl -ane 'print if $F[4] =~ /(\d+)%/ and $1 > 80'
# 分析Apache访问日志(统计IP访问次数)
perl -lane '$ip = $F[0]; $count{$ip}++;
END { print "$_: $count{$_}" for sort {$count{$b} <=> $count{$a}} keys %count }' access.log
# 查找错误日志中的模式
perl -ne 'print "$.: $_" if /(error|fail|critical)/i' error.log
# 分析日志时间分布
perl -ne 'if (/(\d{2}):\d{2}:\d{2}/) { $hour{$1}++ }
END { for (sort keys %hour) { print "$_时: $hour{$_}次\n" } }' access.log
# 监控CPU使用率
top -bn1 | perl -ne 'if (/^\s*(\d+)\s+\S+\s+\S+\s+(\S+)\s+(\S+)/) {
print "PID: $1, CPU: $2%, MEM: $3%\n" if $2 > 10
}'
# 检查服务状态
perl -e 'for (qw(nginx mysql redis)) {
$status = `systemctl is-active $_`;
chomp $status;
print "$_: $status\n";
}'
# 监控网络连接
netstat -an | perl -ne 'print if /ESTABLISHED/ and /:80\s+/'
# 使用CPAN shell安装模块
sudo perl -MCPAN -e shell
install JSON
install LWP::Simple
install DBI
install DateTime
exit
# 命令行安装
sudo perl -MCPAN -e 'install JSON'
# 使用cpanm(推荐)
# 先安装cpanminus
curl -L https://cpanmin.us | perl - --sudo App::cpanminus
# 使用cpanm安装模块
sudo cpanm JSON
sudo cpanm LWP::Simple
sudo cpanm Mojolicious
# 查看已安装模块
perldoc perllocal
或
cpan -l
#!/usr/bin/perl
# JSON处理
use JSON;
my $json = JSON->new->utf8;
my $data = $json->decode('{"name": "Alice", "age": 30}');
print "Name: $data->{name}\n";
# HTTP请求
use LWP::Simple;
my $content = get("http://example.com");
print "Content length: ", length($content), "\n";
# 日期时间处理
use DateTime;
my $dt = DateTime->now;
print "当前时间: ", $dt->ymd, " ", $dt->hms, "\n";
# 数据库访问
use DBI;
my $dbh = DBI->connect("DBI:mysql:database=test;host=localhost", "user", "pass");
my $sth = $dbh->prepare("SELECT * FROM users");
$sth->execute();
while (my $row = $sth->fetchrow_hashref) {
print "User: $row->{name}\n";
}
$dbh->disconnect;
#!/usr/bin/perl
# log_analyzer.pl - 日志分析器
use strict;
use warnings;
use Getopt::Long;
my ($file, $output, $verbose);
GetOptions(
'file=s' => \$file,
'output=s' => \$output,
'verbose' => \$verbose,
'help' => \&usage,
) or usage();
usage() unless $file && -f $file;
# 分析日志
my (%ip_count, %url_count, %status_count, $total_lines);
open my $fh, '<', $file or die "无法打开文件 $file: $!";
while (my $line = <$fh>) {
$total_lines++;
# Apache日志格式解析
if ($line =~ /^(\d+\.\d+\.\d+\.\d+).*?"\w+ (\S+).*?" (\d+)/) {
my ($ip, $url, $status) = ($1, $2, $3);
$ip_count{$ip}++;
$url_count{$url}++;
$status_count{$status}++;
print "分析: $ip - $url - $status\n" if $verbose;
}
}
close $fh;
# 输出结果
if ($output) {
open my $out, '>', $output or die "无法写入文件 $output: $!";
select $out;
}
print "=== 日志分析报告 ===\n";
print "总行数: $total_lines\n\n";
print "IP访问统计(前10名):\n";
foreach my $ip (sort { $ip_count{$b} <=> $ip_count{$a} } keys %ip_count)[0..9] {
printf " %-15s: %d次\n", $ip, $ip_count{$ip};
}
print "\nURL访问统计(前10名):\n";
foreach my $url (sort { $url_count{$b} <=> $url_count{$a} } keys %url_count)[0..9] {
printf " %-30s: %d次\n", $url, $url_count{$url};
}
print "\nHTTP状态码统计:\n";
foreach my $status (sort keys %status_count) {
printf " %3s: %d次\n", $status, $status_count{$status};
}
sub usage {
print <<"USAGE";
用法: $0 --file 日志文件 [选项]
选项:
--file FILE 日志文件路径(必需)
--output FILE 输出文件(默认输出到屏幕)
--verbose 显示详细处理信息
--help 显示此帮助信息
示例:
$0 --file /var/log/apache2/access.log --verbose
$0 --file access.log --output report.txt
USAGE
exit;
}
#!/usr/bin/perl
# batch_processor.pl - 文件批量处理器
use strict;
use warnings;
use File::Find;
use File::Copy;
# 配置
my $source_dir = '/path/to/source';
my $target_dir = '/path/to/target';
my $file_pattern = qr/\.(txt|csv)$/i;
# 创建目标目录
mkdir $target_dir unless -d $target_dir;
# 查找并处理文件
find(sub {
return unless -f && /$file_pattern/;
my $source_file = $File::Find::name;
my $target_file = "$target_dir/$_";
print "处理: $source_file\n";
# 处理逻辑(示例:添加时间戳)
open my $in, '<', $source_file or die "无法读取 $source_file: $!";
open my $out, '>', $target_file or die "无法写入 $target_file: $!";
print $out "# 处理时间: " . scalar(localtime) . "\n\n";
while (my $line = <$in>) {
# 示例处理:去除多余空格
$line =~ s/\s+/ /g;
print $out $line;
}
close $in;
close $out;
print "完成: $target_file\n";
}, $source_dir);
print "批量处理完成!\n";
| 特性 | Perl | Python |
|---|---|---|
| 哲学 | "有多种方法做一件事"(TMTOWTDI) | "应该有一种明显的方法"(Python之禅) |
| 语法 | 灵活但复杂,符号多 | 简洁明了,强制缩进 |
| 正则表达式 | 内置,语法强大 | 通过re模块,相对简单 |
| 文本处理 | 非常强大,原生支持 | 良好,但不如Perl原生 |
| 面向对象 | 5.0+支持,但语法较怪 | 原生支持,简洁优雅 |
| 包管理 | CPAN(非常丰富) | PyPI(同样丰富) |
| 社区 | 稳定,但增长缓慢 | 活跃,快速增长 |
| 适用领域 | 文本处理、系统管理、遗留系统 | Web开发、数据科学、AI |
# 1. 使用perl调试器
perl -d script.pl
# 调试器常用命令
# s 单步执行
# n 下一步(跳过子程序)
# p 表达式 打印表达式
# x 变量 详细打印变量
# l 列出源代码
# b 行号 设置断点
# c 继续执行
# q 退出调试器
# 2. 使用Data::Dumper调试数据
perl -MData::Dumper -e 'my %data = (a=>1, b=>2); print Dumper(\%data)'
# 3. 启用严格模式和警告
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics; # 更详细的警告信息
# 4. 使用Carp模块
use Carp;
carp "这是一个警告";
croak "这是一个致命错误";
# 5. 使用Devel::NYTProf进行性能分析
perl -d:NYTProf script.pl
nytprofhtml
-n和-p都是为输入行隐式添加循环,区别在于:
# -n: 隐式循环,但不自动打印
# 相当于:
# while (<>) {
# # 你的代码
# }
perl -ne 'print if /pattern/' file.txt
# -p: 隐式循环,并自动打印$_
# 相当于:
# while (<>) {
# # 你的代码
# print;
# }
perl -pe 's/foo/bar/' file.txt # 会自动打印修改后的行
# 示例对比:
# 使用-n,需要显式print
perl -ne 's/foo/bar/; print' file.txt
# 使用-p,自动print
perl -pe 's/foo/bar/' file.txt
# -n适用于过滤和条件打印
# -p适用于修改和替换操作
# 方法1:添加shebang行和可执行权限
#!/usr/bin/perl
# 或 #!/usr/bin/env perl
# 使脚本可执行
chmod +x script.pl
# 执行
./script.pl
# 方法2:使用Perl模块创建可执行脚本
# 在脚本开头添加:
#!/usr/bin/perl
use strict;
use warnings;
# 方法3:使用pl2bin转换为二进制(不推荐)
pl2bin script.pl script.bin
# 方法4:使用PAR创建独立可执行文件
# 安装PAR::Packer
cpanm PAR::Packer
# 打包为可执行文件
pp -o myapp script.pl
# 然后可以直接运行 ./myapp
# 方法5:使用App::FatPacker打包依赖
fatpack pack script.pl > packed_script.pl
# 1. 使用严格模式和警告
use strict;
use warnings;
# 2. 预编译正则表达式
my $regex = qr/pattern/;
if ($text =~ $regex) { ... }
# 3. 使用三元运算符代替if-else
my $result = $condition ? $true_value : $false_value;
# 4. 使用map和grep进行列表处理
my @squares = map { $_ * $_ } 1..100;
my @evens = grep { $_ % 2 == 0 } 1..100;
# 5. 避免在循环中重复计算
# 不好
for my $i (1..1000) {
my $len = length($string) + $i;
}
# 好
my $base_len = length($string);
for my $i (1..1000) {
my $len = $base_len + $i;
}
# 6. 使用Benchmark模块测试性能
use Benchmark qw(:all);
timethis(10000, 'your_code()');
# 7. 使用Devel::NYTProf进行性能分析
perl -d:NYTProf script.pl
nytprofhtml # 生成HTML报告
# 8. 使用XS模块加速关键部分
# 如使用PDL进行数值计算
perldoc perlintro开始学习基础cpanPerl模块管理器
perldocPerl文档查看器
provePerl测试运行器
plackupPSGI服务器