Perl 完全指南 / 第 3 章:第一个 Perl 程序
第 3 章:第一个 Perl 程序
“千里之行,始于足下” — 老子
本章将带你编写第一个 Perl 程序,理解脚本结构、运行方式以及 strict 和 warnings 的重要性。
3.1 Hello, World!
创建文件 hello.pl:
#!/usr/bin/env perl
use strict;
use warnings;
print "Hello, World!\n";
运行:
perl hello.pl
输出:
Hello, World!
代码解析
| 部分 | 说明 |
|---|---|
#!/usr/bin/env perl | Shebang 行,告诉系统使用 Perl 解释器 |
use strict; | 启用严格模式(强烈推荐) |
use warnings; | 启用警告(强烈推荐) |
print "Hello, World!\n"; | 打印字符串,\n 是换行符 |
3.2 Shebang 行详解
Shebang 行是脚本文件的第一行,告诉操作系统用什么解释器来运行脚本。
#!/usr/bin/env perl # 推荐:可移植性最好
#!/usr/bin/perl # 直接指定路径(不推荐)
#!/usr/bin/perl -w # 带 -w 参数启用警告
为什么推荐 #!/usr/bin/env perl?
| 写法 | 优点 | 缺点 |
|---|---|---|
#!/usr/bin/env perl | 自动找到 PATH 中的 perl | 极少数系统不支持 env |
#!/usr/bin/perl | 简单直接 | 路径可能不对 |
#!/usr/local/bin/perl | 明确 | 不可移植 |
让脚本可执行
chmod +x hello.pl
./hello.pl
3.3 语句与分号
Perl 中每条语句以分号 ; 结尾:
my $name = "Perl"; # 赋值语句
print "Hello, $name\n"; # 打印语句
代码块用花括号 {} 包裹,块内最后一条语句不需要分号:
if ($age >= 18) {
print "成年人\n"; # 块内最后一条不需要分号
}
3.4 use strict — 严格模式
strict 是 Perl 的编译指令,强制执行三个约束:
strict 的三个限制
| 限制 | 说明 | 示例 |
|---|---|---|
strict 'vars' | 变量必须先声明 | my $x; $x = 1; |
strict 'refs' | 禁止字符串作为引用 | 不能 &{"func"} |
strict 'subs' | 裸字必须是已知子程序 | print hello 会报错 |
不使用 strict 的问题
# 不使用 strict(危险!)
$name = "Perl"; # 拼写错误变成新变量
print $naem, "\n"; # typo,打印空值(无警告)
使用 strict 的安全
# 使用 strict(推荐!)
use strict;
my $name = "Perl"; # 必须用 my 声明
print $naem, "\n"; # 编译报错:Global symbol "$naem" requires explicit package name
3.5 use warnings — 警告模式
warnings 会在运行时对可疑代码发出警告:
use warnings;
my $x;
print $x; # 警告:Use of uninitialized value
my $y = "abc" + 1; # 警告:Argument "abc" isn't numeric
warnings 的常见警告
| 警告 | 原因 |
|---|---|
Use of uninitialized value | 使用未初始化的变量 |
Name "main::x" used only once | 变量只使用了一次(可能是 typo) |
Argument "abc" isn't numeric | 非数字参与数值运算 |
Possible unintended interpolation | 字符串中可能有意外的变量插值 |
print() on closed filehandle | 向已关闭的文件句柄写入 |
-w 命令行参数 vs use warnings
# 命令行启用(全局,包括所有模块)
perl -w script.pl
# 脚本内启用(推荐,仅限当前文件)
# 在脚本顶部使用 use warnings;
3.6 注释
Perl 使用 # 开始单行注释。没有多行注释语法:
# 这是单行注释
my $x = 1; # 行尾注释
# 多行注释需要每行都加 #
# 第一行
# 第二行
# 第三行
# 也可以用 POD 格式实现"多行注释"(不推荐)
=begin comment
这是多行注释
Perl 解释器会忽略 POD
=end comment
=cut
3.7 代码风格基础
缩进
推荐使用 4 个空格缩进(社区惯例):
#!/usr/bin/env perl
use strict;
use warnings;
sub greet {
my ($name) = @_;
if (defined $name) {
print "Hello, $name!\n";
} else {
print "Hello, stranger!\n";
}
}
greet("Perl");
命名规范
| 类型 | 风格 | 示例 |
|---|---|---|
| 标量变量 | snake_case | $user_name |
| 数组 | snake_case | @file_list |
| 哈希 | snake_case | %config_data |
| 子程序 | snake_case | parse_input() |
| 常量 | UPPER_CASE | MAX_RETRY |
| 包名 | CamelCase | MyApp::Utils |
3.8 运行 Perl 脚本的多种方式
方式 1:直接运行(最常见)
perl script.pl
方式 2:可执行脚本
chmod +x script.pl
./script.pl
方式 3:命令行 one-liner
perl -e 'print "Hello\n"'
方式 4:从 STDIN 读取
echo 'print "Hello\n"' | perl
方式 5:管道处理
cat data.txt | perl -ne 'print if /pattern/'
常用命令行参数
| 参数 | 说明 | 示例 |
|---|---|---|
-e | 执行一行代码 | perl -e 'print 1' |
-n | 逐行读取(隐式循环) | perl -ne 'print if /foo/' |
-p | 逐行读取并打印 | perl -pe 's/foo/bar/g' |
-i | 原地编辑文件 | perl -i -pe 's/foo/bar/g' file.txt |
-l | 自动添加换行 | perl -lne 'print' |
-c | 检查语法(不运行) | perl -c script.pl |
-d | 启动调试器 | perl -d script.pl |
-w | 启用警告 | perl -w script.pl |
-M | 加载模块 | perl -MJSON::XS -e '...' |
3.9 代码检查与调试
语法检查
# 只检查语法,不运行
perl -c script.pl
输出示例:
script.pl syntax OK
使用 Perl::Tidy 格式化代码
cpanm Perl::Tidy
perltidy script.pl
使用 Perl::Critic 检查代码质量
cpanm Perl::Critic
perlcritic script.pl
perlcritic --severity 3 script.pl # 只显示严重问题
内置调试器
perl -d script.pl
调试器常用命令:
| 命令 | 说明 |
|---|---|
n | 执行下一行(不进入子程序) |
s | 执行下一行(进入子程序) |
c | 继续运行到断点 |
b <行号> | 设置断点 |
p <表达式> | 打印表达式值 |
x <变量> | 详细打印变量内容 |
q | 退出调试器 |
h | 帮助 |
3.10 第一个实用脚本
一个简单但实用的脚本——统计文件中的单词频率:
#!/usr/bin/env perl
use strict;
use warnings;
# 检查命令行参数
die "用法: $0 <文件名>\n" unless @ARGV == 1;
my $filename = $ARGV[0];
die "文件 '$filename' 不存在\n" unless -f $filename;
# 统计单词频率
my %word_count;
open my $fh, '<', $filename or die "无法打开文件: $!\n";
while (my $line = <$fh>) {
chomp $line;
# 移除标点,转小写
$line =~ s/[[:punct:]]//g;
my @words = split /\s+/, lc($line);
for my $word (@words) {
next unless $word; # 跳过空字符串
$word_count{$word}++;
}
}
close $fh;
# 按频率排序输出
print "文件: $filename\n";
print "=" x 40, "\n";
my $rank = 0;
for my $word (sort { $word_count{$b} <=> $word_count{$a} } keys %word_count) {
$rank++;
printf "%3d. %-20s %d 次\n", $rank, $word, $word_count{$word};
last if $rank >= 20; # 只显示前 20 个
}
运行:
perl word_freq.pl somefile.txt
3.11 Perl one-liners
Perl 最强大的特性之一是 one-liner(一行命令):
# 打印包含 "error" 的行
perl -ne 'print if /error/' logfile.txt
# 替换文件中的文本
perl -i -pe 's/old/new/g' file.txt
# 打印第 3-7 行
perl -ne 'print if 3..7' file.txt
# 统计行数
perl -lne 'END { print $. }' file.txt
# 去除重复行
perl -ne 'print unless $seen{$_}++' file.txt
# 格式化 CSV
perl -F, -lane 'print join "\t", @F' data.csv
# 反转每行
perl -lne 'print scalar reverse' file.txt
one-liner 参数说明
| 参数 | 说明 |
|---|---|
-n | 为每一行执行代码(不自动打印) |
-p | 为每一行执行代码(自动打印) |
-i | 原地编辑(就地修改文件) |
-e | 指定代码 |
-l | 自动添加换行符 |
-a | 自动分割(类似 awk) |
-F | 指定分割模式 |
本章小结
| 要点 | 内容 |
|---|---|
| Shebang | #!/usr/bin/env perl 确保可移植性 |
| strict | 必须启用,强制变量声明,避免 typo |
| warnings | 必须启用,运行时警告可疑代码 |
| 分号 | 每条语句以 ; 结尾 |
| 注释 | 使用 #,没有多行注释 |
| 运行方式 | perl script.pl、可执行脚本、one-liner |
| 代码检查 | perl -c(语法)、perlcritic(质量) |
练习
- 编写一个脚本,打印你的名字、年龄和爱好
- 故意去掉
use strict,使用未声明的变量,观察行为 - 编写一个 one-liner,统计
/etc/passwd中有多少行 - 编写一个脚本,读取一个文件并打印其行数
- 使用
perl -c检查你的脚本语法