商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > Perl命令行应用程序详解

Perl命令行应用程序详解

  发布于2026-06-29 阅读(0)

扫一扫,手机访问

Perl——Practical Extraction and Report Language——拥有大量命令行参数,善用它们能让你的脚本精简到极致,甚至一行命令就搞定所有事情。这篇文章就来系统梳理一下那些最常用的命令行参数。

Perl命令行应用程序详解

命令行调用

复制代码 代码如下:

perl [ -sTtuUWX ]
[ -hv ] [ -V[:configvar] ]
[ -cw ] [ -d[t][:debugger] ] [ -D[number/list] ]
[ -pna ] [ -Fpattern ] [ -l[octal] ] [ -0[octal/hexadecimal] ]
[ -Idir ] [ -m[-]module ] [ -M[-]'module...' ] [ -f ]
[ -C [number/list] ]
[ -P ]
[ -S ]
[ -x[dir] ]
[ -i[extension] ]
[ [-e|-E] 'command' ] [ -- ] [ programfile ] [ argument ]...

[开关项描述]

-0

规定记录分隔符。

-0<数字>

(用8进制表示)指定记录分隔符($/变量),默认为换行。

-00

段落模式,即以连续换行为分隔符。

-0777

禁用分隔符,将整个文件作为一个记录。

-a

-n-p 搭配,打开自动拆分模式。默认按空白字符拆分,结果存入@F,相当于@F = split ''。可以通过 -F 自定义分隔符。举个例子:

复制代码 代码如下:

date | perl -ane 'print "$F[0]n"';

-c

只检查 Perl 脚本语法,不执行。每次修改脚本后第一时间用它来捉语法错误。

-d

启动 Perl 调试器。

-D

设置调试标记。例如 -D14 可以观察脚本的执行过程。使用前请确认调试器已正确安装。

-e command

直接在命令行执行 Perl 代码,无需写脚本文件。这是单行命令的基石。

-F pattern

指定拆分输入行时的模式。模式是正则表达式,可以放在斜杠、单引号或双引号中。例如 -F/:+/ 表示按一个或多个冒号拆分。如果同时使用 -a,则自动生效。

-h

打印 Perl 命令行选项列表。

-i extension

启用原位编辑模式。使用 <> 循环遍历文件时,如果需要修改原文件,-i 就派上用场了。如果提供扩展名(如 .bak),则原始文件会被备份为 原文件名.扩展名,然后修改写入原文件。如果不提供扩展名,则直接覆盖。

-I directory

-P 配合,告诉 C 预处理程序去哪里查找包含文件。默认路径包括 /usr/include/usr/lib/perl 和当前目录。

-l digits

启用自动行尾处理。与 -n-p 一起使用时,会自动移除输入行的换行符,并将输出行附加换行符。如果不指定数字,则把 $/ 的当前值赋给 $\。简单理解:-l 同时做了两件事——自动 chomp 输入分隔符,并在 print 时自动加换行。

复制代码 代码如下:

-m [-] module
-M [-] module
-M [-] module'
-[mM] module =
arg [,arg]..
-m module

在执行 Perl 脚本之前调用 use 方法。其中 -M 相当于 use Module;-m 相当于 use Module ();(即不导入默认符号)。方括号中的短横线表示将 use 替换为 no

-n

让 Perl 隐式循环遍历所有文件。相当于 while (<>) { 脚本; }。每一行默认保存在 $_ 中。

-p

类似 -n,但会在循环末尾自动打印 $_。相当于 while (<>) { 脚本; print; }。简单来说,-p 适合完全处理文件,-n 适合选择性输出。

-P

在 Perl 编译之前先通过 C 预处理程序处理脚本。

-s

启用自定义开关解析。脚本名之后、文件名参数之前的开关会被解析为对应的标量变量(如 -abc 会生成 $abc 并赋值为 1),并从 @ARGV 中删除。

-S

如果脚本首行不是 #!/usr/bin/perl,则让 Perl 在 PATH 环境变量中搜索脚本。

-T

强制打开“污染”检查(taint mode),常用于测试 setuid/setgid 程序,也推荐用于 CGI 脚本。

-u

编译后产生核心转储(仅 Unix 系统)。

-U

允许 Perl 执行不安全操作,例如超级用户断开目录链接。

-v

打印 Perl 版本信息。

-V

打印重要配置项和 @INC 数组的汇总。

-V:NAME

打印指定配置变量 NAME 的值。

-w

打印警告信息,包括保留字误用、文件句柄错误等。

-W

启用所有警告,即使局部代码中用 no warnings 关闭了也无效。

-x directory

忽略 #!/usr/bin/perl 行之前的任何文本。如果指定了目录名,Perl 会在执行前自动切换到该目录。

-X

关闭所有警告。

另外提一句:-p-n 都隐式地把每一行保存在 $_ 中,区别仅在于 -p 会自动打印 $_

安全网参数

有三个参数堪称“安全网”,尤其当你用 Perl 玩一些“聪明”或疯狂的想法时,它们能让错误提前现形。经验丰富的 Perl 程序员几乎离不开它们。

首先是 -c。编译但不执行,只检查语法错误。每次修改脚本后先跑一遍 perl -c program.pl,确保编译通过。在输入少量代码时就检查,比后面面对几百行代码再 debug 轻松得多。

第二个是 -W,它开启所有警告,能揪出潜在的 bug。不过 Perl 5.6.0 之后推荐在脚本内使用 use warnings;,因为更灵活。

第三个是 -T,进入 taint 模式。Perl 会怀疑所有来自外部的数据(命令行、文件、CGI 输入),这些数据被“污染”后不能直接用于 system 调用、open 等危险操作。要使用它们,必须通过正则表达式“去污染”。taint 模式本身内容很多,这里不展开,但如果你在写 CGI 等需要接收用户输入的程序,强烈推荐开启 taint 模式。

另外 -d 参数进入调试器模式,详细内容可参考 perldoc perldebug 或 Richard Foley 的 Perl Debugger Pocket Reference

使用模块

下面几个参数让命令行上的 Perl 程序更简洁。-e 可以直接执行代码,比如一行搞定“Hello World”:

复制代码 代码如下:

$ perl -e 'print "Hello Worldn"'

多个 -e 可以按顺序执行:

复制代码 代码如下:

$ perl -e 'print "Hello ";' -e 'print "Worldn"'

引入模块时,-M 比在 -e 中用 use 更方便:

复制代码 代码如下:

$ perl -MLWP::Simple -e 'print head "http://www.example.com"'

-M 等同于 use Module;,包含默认导入。如果不想要默认导入,就用 -m,它相当于 use Module ();。例如下面的例子因为 head 函数是默认导入,使用 -m 时不会被导入,所以什么也输出:

复制代码 代码如下:

$ perl -mLWP::Simple -e 'print head "http://www.example.com"'

-m-M 还支持在 = 后附加参数,比如引入 :standard 标签:

复制代码 代码如下:

$ perl -MCGI=:standard -e 'print header'

要引入多个参数,可以用引号加逗号分隔:

复制代码 代码如下:

$ perl -MCGI='header,start_html' -e 'print header,start_html'

隐式循环

-n-p 为逐行处理文件提供了循环框架。

复制代码 代码如下:

$ perl -n -e 'some code' file1

相当于:

复制代码 代码如下:

LINE:
while (<>) {
# your code goes here
}

每一行自动存入 $_。下面的例子输出行号和内容:

复制代码 代码如下:

$ perl -n -e 'print "$. - $_"' file

-p 会自动调用 print,所以同样的效果可以写成:

复制代码 代码如下:

$ perl -p -e '$_ = "$. - $_"' filename

注意隐式循环中有一个 LINE: 标签,可以用 next LINE 直接跳到下一个输入记录,这在多层嵌套时非常有用:

复制代码 代码如下:

$ perl -n -e 'next LINE unless /pattern/; print $_'

当然也可以简化成 print unless /pattern/。如果需要在循环前后做额外处理,可以使用 BEGINEND 块。下面这个例子统计文本文件中的总字数:

复制代码 代码如下:

$ perl -ne 'END { print $t } @w = /(w+)/g; $t += @w' file.txt

如果再加上 -a,自动拆分模式会把每行按空白分割成数组 @F,上面的代码可以更简洁:

复制代码 代码如下:

$ perl -ane 'END {print $x} $x += @F' file.txt

通过 -F 可以自定义拆分规则。例如按非单词字符拆分:

复制代码 代码如下:

$ perl -F'W' -ane 'END {print $x} $x += @F' file.txt

一个经典的例子:分析 Unix 密码文件(/etc/passwd),按冒号拆分,统计每个 shell 路径被多少用户使用:

复制代码 代码如下:

$ perl -F':' -ane 'chomp($F[6]); $s{$F[6]}++; END{print"$_:$s{$_}n" for keys %s}' /etc/passwd

输出类似:

复制代码 代码如下:

/usr/sbin/nologin : 3
/bin/sh : 18
/bin/sync : 1
/bin/bash : 2
/bin/false : 9

数据分隔符

之前提到过 $/(输入记录分隔符)和 $\(输出记录分隔符)。$/ 默认是换行符,所以一次读一行。$\ 默认为空,因此 print 时需要手动加 \n。在命令行中,-0(零)对应 $/-l(字母 L)对应 $\-0 后面可以跟八进制或十六进制数值,例如 -00 进入段落模式(连续换行分隔),-0777 进入 slurp 模式(一次读入整个文件)。-l 单独使用有两个效果:一是自动 chomp 输入分隔符,二是把 $/ 的值赋给 $\,这样 print 时自动加换行。个人常常使用 -l 来省去末尾的 \n

复制代码 代码如下:

$ perl -le 'print "Hello World"'

原位编辑

配合 -i 参数,可以原地修改文件,而不需要 I/O 重定向。例如将所有 PHP 替换为 Perl(整词匹配):

复制代码 代码如下:

$ perl -i -pe 's/bPHPb/Perl/g' file.txt

如果想保留备份,就加个扩展名:

复制代码 代码如下:

$ perl -i.bak -pe 's/bPHPb/Perl/g' file.txt

处理后的结果写入 file.txt,原始文件则被重命名为 file.txt.bak

打开Perl的taint模式

如果程序从外部接收数据,并且这些数据会影响到程序之外的东西(比如系统调用),那么就应该用 -T 开启 taint 模式。Perl 会检查数据是否被“污染”,如果未经处理就用于危险操作,会抛出一个致命错误。去污染的唯一方法是用正则表达式匹配并提取你想要的部分,从而明确描述数据的格式。例如,期望收到一个单词字符:

复制代码 代码如下:

if ($data =~ /^(w+)$/) {
$data = $1;
} else {
die "Error: tainted data found: $datan";
}

Perl命令行调试

缺省的 Perl 调试器就是解释器本身,启动方式很简单:perl -d test.pl。进入交互界面后,常用命令如下(所有命令在调试提示符下输入,大小写有关):

  • h:显示帮助。
  • |h:分页显示帮助。
  • p 表达式:打印变量或表达式的值(不显示复杂结构)。
  • x 表达式:打印变量值,对复杂数据以可读形式展示。
  • V 包名 变量列表:显示指定包内的变量(包名默认 main)。
  • X 变量列表:显示当前包内的变量。
  • T:调用栈回退一级。
  • s:单步执行,进入子函数(step into)。
  • n:单步执行,越过子函数(step over)。
  • c 行号/函数名:执行到指定行或函数。
  • l:显示未执行的一屏代码。
  • l min-max:显示指定行范围。
  • /模式:向前查找。?模式:向后查找。
  • b 行号 [条件]:设置断点。b 函数名 [条件]:函数断点。d 行号:删除断点。D:删除所有断点。
  • a 行号 命令:添加附加操作(执行该行前先执行命令)。
  • W 表达式:添加监视项。
  • !number:重复执行之前第 number 次调试命令。
  • !!命令:执行 shell 命令而不退出调试器。
  • q:退出。

更多细节可参考 perldoc perldebug

更多信息

Perl 命令行参数远不止这些,本文只列出了最实用的一部分。完整列表请参考 perlrun 文档。

命令行的运用

Perl 在命令行下完全可以替代 sed、awk 等工具。有经验的程序员不应回避那些看似“丑陋”但高效的快速解决方法。

Perl单行命令示例

先看参数如何被接收:

复制代码 代码如下:

perl -MData::Dumper -e 'print Dumper @ARGV' a b -w
$VAR1 = [
'a',
'b',
'-w'
];

-e 后的内容被当作脚本执行。-M 导入模块。注意单引号比双引号更安全,因为 shell 不会转义里面的变量。

复制代码 代码如下:

perl -e 'print "$$n"'
5719

上例打印当前进程 PID,单引号保护了 $$ 不被 shell 解释。

原地替换:

复制代码 代码如下:

perl -pi -e 's/aaa/bbb/' filename

类似 grep 过滤:

复制代码 代码如下:

perl -ne 'print if /^int/' filename

加行号打印:

复制代码 代码如下:

perl -n -e 'print "$. - $_"' filename

使用 -p 简化:

复制代码 代码如下:

perl -pe '$_ = "$. $_"' filename

利用 -a-F 进行字段处理:

复制代码 代码如下:

perl -lane 'print $F[0] + $F[-2]'

打印从 START 到 END 之间的行:

复制代码 代码如下:

perl -ne 'print if /^START$/ .. /^END$/'

打印指定行号范围:

复制代码 代码如下:

perl -ne 'print if $. >= 15; exit if $. >= 17;'

原地替换并备份:

复制代码 代码如下:

perl -p -i.bak -e 's/bfoob/bar/g' *.c

反向每一行:

复制代码 代码如下:

perl -ne 'print scalar reverse $_' test

替换

所有 C 程序中的 foo 替换为 bar,旧文件备份为 .bak

复制代码 代码如下:

perl -p -i.bak -e 's/bfoob/bar/g' *.c

将每个文件中的数字加一:

复制代码 代码如下:

perl -i.bak -pe 's/(d+)/ 1 + $1 /ge' file1 file2 ....

\r\n 替换为 \n(类似 dos2unix):

复制代码 代码如下:

perl -p -i -e 's/rn/n/g' file

反向(类似 unix2dos):

复制代码 代码如下:

perl -pie 's/n/rn/g' file

取出文件的一部分

显示字段 0-4 和字段 6(默认空格分隔):

复制代码 代码如下:

perl -lane 'print "@F[0..4] $F[6]"' file

如果分隔符是冒号(如 /etc/passwd):

复制代码 代码如下:

perl -F: -lane 'print "@F[0..4]n"' /etc/passwd

显示 START 和 END 之间的部分:

复制代码 代码如下:

perl -ne 'print if /^START$/ .. /^END$/' file

不显示中间部分:

复制代码 代码如下:

perl -ne 'print unless /^START$/ .. /^END$/' file

显示前 50 行:

复制代码 代码如下:

perl -pe 'exit if $. > 50' file

跳过前 10 行:

复制代码 代码如下:

perl -ne 'print unless 1 .. 10' file

显示第 15 到 17 行:

复制代码 代码如下:

perl -ne 'print if 15 .. 17' file

每行取前 80 个字符:

复制代码 代码如下:

perl -lne 'print substr($_, 0, 80) = ""' file

每行丢弃前 10 个字符:

复制代码 代码如下:

perl -lne 'print substr($_, 10) = ""' file

搜索

查找包含 comment 的行:

复制代码 代码如下:

perl -ne 'print if /comment/' duptext

查找不含 comment 的行:

复制代码 代码如下:

perl -ne 'print unless /comment/' duptext

查找包含 commentapple 的行:

复制代码 代码如下:

perl -ne 'print if /comment/ || /apple/' duptext

计算

计算第 5 字段和倒数第 2 字段之和:

复制代码 代码如下:

perl -lane 'print $F[4] + $F[-2]'

排序和反转

文件按行排序:

复制代码 代码如下:

perl -e 'print sort <>' file

文件按段落排序:

复制代码 代码如下:

perl -00 -e 'print sort <>' file

合并多个文件后整体排序:

复制代码 代码如下:

perl -0777 -e 'print sort <>' file1 file2

文件按行反转:

复制代码 代码如下:

perl -e 'print reverse <>' file1

数值计算

十进制转十六进制:

复制代码 代码如下:

perl -ne 'printf "%xn",$_'

十进制转八进制:

复制代码 代码如下:

perl -ne 'printf "%on",$_'

十六进制转十进制:

复制代码 代码如下:

perl -ne 'print hex($_)."n"'

八进制转十进制:

复制代码 代码如下:

perl -ne 'print oct($_)."n"'

简易计算器:

复制代码 代码如下:

perl -ne 'print eval($_)."n"'

批量重命名文件

利用 File::Find 模块遍历目录并改名。例如将 帝王之死001.mp3 重命名为 01.mp3

复制代码 代码如下:

$ ls
帝王之死001.mp3 帝王之死006.mp3
$ perl -MFile::Find -e 'find sub{ rename $_,substr($1,1,2).".mp3" if /(d+).mp3$/;}, "." '
$ ls
01.mp3 06.mp3

更复杂的例子,去掉中文引号、替换分隔符等,这里不再一一展开,核心就是 find 结合正则表达式。

在命令行下查看当前目录下的目录

使用内置 File::Find 列出所有子目录(包括深层):

复制代码 代码如下:

perl -MFile::Find -E 'find sub{ print "$_," if(-d && length >1) }, $File::Find::prune = 1, "." '

使用 File::Find::Rule 更直观,只列一级目录:

复制代码 代码如下:

perl -MFile::Find::Rule -E 'say for grep $_ ne ".", File::Find::Rule->maxdepth(1)->directory->in(".");'

对目录下的文件进行大小写修改

将大写目录名改为小写:

复制代码 代码如下:

$ ls
CD1 CD2 CD3 CD4 CD5 CD6
$ perl -MFile::Find -e 'find sub{ rename $_,lc($1) if /(w+d$)/;}, "." '
$ ls
cd1 cd2 cd3 cd4 cd5 cd6

统计相关的tcp连接情况

查看 IP 尾数为 9、端口 80 的所有连接:

复制代码 代码如下:

netstat -naut|grep 9:80|perl -F's+' -alne '$F[4]=~/(.*):d+/;$F[4]=$1;$s{$F[4]}++;' -e 'END { foreach (sort {$a<=>$b} keys %s){print "$_ : $s{$_}"} }'

按连接数降序排列,显示前 20 个 IP:

复制代码 代码如下:

netstat -naut|grep 9:80|perl -F's+' -alne '$F[4]=~/(.*):d+/;$F[4]=$1;$s{$F[4]}++;' -e 'END {foreach (sort {$s{$b}<=>$s{$a}} keys %s){print "$_ : $s{$_}"} }' |head -20

统计连接状态:

复制代码 代码如下:

netstat -naut|grep 9:80|perl -F's+' -alne '$s{$F[5]}++;' -e 'END { foreach (keys %s){chomp($_);print "$_ : $s{$_}"} }'

统计文本文件行数,有多种写法,但实测 wc -l 效率最高。

复制代码 代码如下:

perl -le 'open FILE, "file_name"; @_=; print $.'
perl -e 'print scalar(()=<>),"n"' file_name
perl -wE'say~~(()=<>)' file_name
perl -e'print scalar(()=<>)' file_name
perl -lne 'END{print $.}' file_name
perl -le 'print $==()=<>' file_name
perl -ne 'print $. if eof' file_name

其他

启动交互式 Perl 调试器:

复制代码 代码如下:

perl -de 1

查看 @INC 路径:

复制代码 代码如下:

perl -le 'print for @INC'

perl 生成随机密码

核心是利用 rand 函数。生成 25 到 75 之间的随机数:

复制代码 代码如下:

$random = int( rand(51)) + 25;
print "$randomn";

从数组中随机取一个元素:

复制代码 代码如下:

$elt = $array[ rand @array ];
$elt = $array[ int( rand(0+@array) ) ];

生成 8 位包含特殊字符的随机密码:

复制代码 代码如下:

@chars = ( "A" .. "Z", "a" .. "z", 0 .. 9, qw(! @ $ % ^ & *) );
$password = join("", @chars[ map { rand @chars } ( 1 .. 8 ) ]);

更灵活的方式:

复制代码 代码如下:

use strict;
use warnings;
sub random_pwd {
my $length = shift;
my @chars = (0 .. 9, 'a' .. 'z', 'A' .. 'Z');
return join '', @chars[ map rand @chars, 0 .. $length ];
}
print random_pwd(42);

一行命令生成 42 位密码:

复制代码 代码如下:

perl -le "print map { ('a'..'z', 'A'..'Z', '0'..'9')[rand 62] } 1..42"

也可以调用 String::Random 模块:

复制代码 代码如下:

use strict;
use warnings;
use String::Random 'random_regex';
print random_regex('[a-zA-Z]{42}'), "n";

相关问题:Perl one-liner 中处理单引号

在命令行中,单引号嵌套容易出问题。假设你想输出带单引号的字符串:

复制代码 代码如下:

echo "a,b" | perl -F',' -lane 'print $F[0];'
'a'

如果直接试图包裹单引号,可能会失败。解决办法:1)使用双引号包裹外层,内部用转义;2)使用 ASCII 码 \047。例如:

复制代码 代码如下:

echo "a,b" | perl -F',' -lane 'print "'''$F[0]'''";'
'a'

或者:

复制代码 代码如下:

echo "a,b" | perl -F',' -lane 'print "$F[0]\047";'
a'

这些技巧在实际的单行命令中很实用,值得收藏。

本文转载于:https://www.jb51.net/article/60771.htm 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

产品推荐