perl -n、perl -p、perl -a 常被写成命令行技巧,但课程验收不能只看屏幕上几行输出。Perl 5.38.2 的 perlrun 说明里,-n 给程序包一层 while (<>) { ... },不会自动打印;-p 同样包循环,但每轮末尾打印当前 $_;-a 在隐式循环里把 split 结果放进 @F,并且文档明说 -a 会隐含设置 -n,-F 会隐含设置 -a 和 -n。这些开关改变的是解释器包裹源码的方式,不是另一套迷你语言。

累计实验 examples/perl-language/experiments/course-oneliners.pl 先写入三行 TSV,再运行三条单行脚本:-ane 'print if $F[0] eq "INFO"' 过滤 INFO,-pe 's/^WARN/ERROR/' 生成替换后的流,-F'\t' -lane 'print "$F[0]:$F[1]"' 输出字段对。实验还把第一条单行脚本还原成完整脚本:显式 while (<>)、显式 split、条件 print,并断言在当前三行、无空字段的样本里,完整脚本输出与 -ane 输出相同。

1
2
3
4
while (defined(my $line = <>)) {
my @fields = split /\t/, $line, -1;
print $line if $fields[0] eq 'INFO';
}

反例是默认自动拆分。-a 不带 -F 时走默认空白拆分,连续空白会被当作分隔空白处理;TSV 的空字段、尾部空字段和普通空白分隔不是同一个契约。上面的完整脚本用 split /\t/, $line, -1 保留尾部空字段;它在当前样本上和 -ane 输出一致,但一般 TSV 字段契约不同于默认自动拆分。课程要求能还原,是为了把这种差异写出来,而不是把 one-liner 当成魔法缩写。

另一个反例是原地编辑。-i.bak -pe 's/^WARN/ERROR/' file 会改目标文件,并留下 .bak;如果只看 STDOUT,就会误以为没有输出代表没有副作用。测试实际核对 oneliner.inplace=ERROR\tworker 和 oneliner.backup=WARN\tworker,证明备份与目标各自存在。-i 仍然不能替代版本控制、原子写入或断电恢复;它只证明这条 Perl 入口如何修改文件。

来源固定在 Perl 5.38.2:pod/perlrun.pod 对 -n、-p、-a、-F 的说明,对外链接可查 perlrun 5.38.2;split 的细节见 split 5.38.2。练习:把 -ane 改成 -ne,仍然读取同一文件,$F[0] 还会可靠吗?答案是不会;没有 -a 就不会自动填充 @F,应手写 my @fields = split,或保留 -a 并明确 -F。