Perl命令行应用程序详解

时间:2021-05-22

perl - Practical Extraction and Report Language,Perl有很多命令行参数,通过它可以让你的程序更简练,并且可以写出很多只有一行命令的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

设置 Perl 的调试标记(请先检查 Perl 的安装情况,确保已经安装了调试器),若要观察 Perl 是如何执行脚本的,可使用 -D14。

-e command

用于再命令行而不是在脚本中执行 Perl 命令。

-F pattern

规定拆分输入行时使用的模式。模式是位于斜杠、单引号或双引号之间的正则表达式。例如,-F/:+/ 表示在一个或多个冒号上拆分输入行,如果 -a 仍然起作用的话,则打开它。

-h

打印 Perl 的命令选项列表。

-i extension

在使用 <> 循环遍历文件时启用原位编辑模式。 如果没有规定扩展名的话,则原位修改各行内容,否则使用扩展名来修改输入文件名(以便充当备份文件),并使用原位编辑的原文件名创建输出文件。 这也是所有 print 语句选择的文件句柄。

-I directory
与 -P选项一起使用,负责告诉 C 预处理程序查找包含的文件,其默认目录包括 /usr/included、/usr/lib/perl 以及当前目录。

-1 digits
启用自动行结束处理。如果使用了 -n 或者 -p 选项,则去掉终止符。把位数(八进制) 赋值给 $\ ,并将行终止符添加到 print 语句中。如果没有规定位数的话,则将 $\ 设置为 $/ 的当前值。

-l
对输入内容自动chomp,对输出内容自动添加换行。使用 -l 有两个效果,第一自动 chomp 输入分隔号,第二 把$/ 值付给 $\ (这样 print 的时候就会自动在末尾加 \n)

复制代码 代码如下:
-m [-] module
-M [-] module
-M [-] module'
-[mM] module =
arg [,arg]..
-m module

在执行 Perl 脚本之前执行 use 方法。

-M module
再执行 Perl 脚本之前执行 use 方法。如果添加附加的文本,则可使用引号。方括号中的短横线表示把 use 指令替换为 no。

-n
使 Perl 隐式地循环遍历指定的文件,并只打印规定的行。自动循环,相当于 while(<>) { 脚本; }

-p
使 Perl 隐式地循环遍历指定的文件,同时打印所有的行。自动循环+自动输出,相当于 while(<>) { 脚本; print; }

-P
使要运行的脚本在 Perl 编译之前通过 C 预处理程序。

-s
再脚本名之后、文件名参数之前启用开关项解析,并从@ARGV 数组中删除所有找到的开关项。将开关项设置为同名的标量型变量,并将标量赋值为 1 。例如,-abc 在脚本中将转换为 $abc。

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

-T
强制打开“污染“ 检查,用于测试脚本,一般只用在 setuid 或 setgid 程序上。推荐自行检查 CGI 脚本。

-u
编译后产生脚本的核心转储(基于 UNIX 系统)。

-U
允许 Perl 执行不安全的操作,如果是超级用户的话,则断开目录链接。

-v
打印 Perl 的版本信息。

-V
打印最重要的 Perl 配置项和数组 @INC 中当前值的汇总。

-V:NAME
打印 NAME 的值,其中 NAME 是配置变量。

-w
打印警告信息,包括错误使用保留字、文件句柄、子例程等情况。

-W
启用所有警告,而不论是否已经用 no warnings 关闭了本地警告。

-x directory
忽略 #!/usr/bin/perl 行之前的任何文本。如果将目录名当作 -x 开关的参数,则 Perl 会在开始执行脚本之前自动切换到该目录。

-X
关闭所有警告。

每一行将缺省保存在 $_,-p 和 -n 一样,但是还会打印 $_ 的内容。

请注意:-p 开关和 -n 开关的使用。当您想显式打印数据时,使用 -n 开关。-p 开关隐式地将 print $_ 语句插入到 -n 开关所产生的循环中。因此,-p 开关更适用于对文件进行的完全处理,而 -n 开关更适用于选择性文件处理,这样的处理只需打印特定数据。

安全网参数
有三个参数我认为可以起到“安全网”的作用,因为它们可以让你避免犯错,特别是当你在使用 Perl 尝试一些特别聪明(或这愚蠢)的想法时,错误难免会发生。有经验的 Perl 程序员常常使用这三个参数来提前找到错误所在。

-c 是第一个。这个参数编译 Perl 程序但并不真正运行它,由此检查所有语法错误,每次修改 perl 程序之后我都会立刻使用它来找到任何语法错误。

复制代码 代码如下:
$ perl -c program.pl

这保证了程序依然可以编译。很显然,当你输入一小段代码之后立即进行检查,比起一下子输入几百行代码然后开始 debug 要容易很多。

-W 是第二个参数。它会提示你任何潜在的bug。Perl 5.6.0 之后的版本已经用 use warnings; 替换了-w。你应该使用 use warnings 因为它要比 -w 更灵活。

-T 是第三个参数。它让 perl 出于了 taint 模式中。在这个模式里,Perl 会质疑任何程序外传来的数据。例如从命令行读取,外部文件里读取或是 CGI 程序里传来的数据。这些数据在 -T 模式里都会被 Tainted(污染),Tainted 数据不可以被用来和外部交互。例如使用在 system 调用和用作 open 的文件名,关于什么数据会被Tainted,请参阅perlsec 文档,那里有一个完整的列表。

要想使用 Tainted 的数据就必须 untaint这个数据。untaint是通过正则表达式来实现的,关于 taint 本身的内容足够写一篇单独的文章,所以这里我不会太多的讲述 taint 模式。如果你要编写的程序(例如 CGI 程序)需要从从用户那里接受不可知的输入,我推荐使有 taint 模式。

还有一个值得一提的参数是 -d,它将让 Perl 处于 Debugger 模式。这个话题内容非常多,我推荐阅读文档 ‘perldoc perldebug'或 Richard Foley 的 Perl Debugger Pocket Reference 一书.

使用模块
下面的几个 Perl 参数可以让短小的 Perl 程序很容易的在命令行上运行,-e 可以让 Perl代码在命令行上被编译器直接执行。例如,我们可以直接在命令行上运行“Hello World” 程序而不用把它写称 Perl 程序。
复制代码 代码如下:
$ perl -e 'print "Hello World\n"'

多个 -e 也可以同时使用,运行顺序根据它出现的位置。
复制代码 代码如下:
$ perl -e 'print "Hello ";' -e 'print "World\n"'

象所有的 Perl 程序一样,只有程序的最后一行不需要以 ; 结尾,你也可以用 -e 来引用模块,但 -M 让它变得更容易。

复制代码 代码如下:
$ perl -MLWP::Simple -e 'print head "http://ment/ || /apple/' duptext

相同的功能就要用到egrep了,语法比较复杂……

计算
计算字段4和倒数第二字段之和:
复制代码 代码如下:
perl -lane 'print $F[4] + $F[-2]'

要是用awk,就得写成 awk '{i=NF-1;print $5+$i}'

排序和反转
文件按行排序:
复制代码 代码如下:
perl -e 'print sort <>' file

相当于简单的sort命令。

文件按段落排序:

复制代码 代码如下:
perl -00 -e 'print sort <>' file

多个文件按文件内容排序,并返回合并后的文件:

复制代码 代码如下:
perl -0777 -e 'print sort <>' file1 file2

文件按行反转:

复制代码 代码如下:
perl -e 'print reverse <>' file1

相应的命令有吗?有,tac(cat的反转)

数值计算
10进制转16进制:

复制代码 代码如下:
perl -ne 'printf "%x\n",$_'

10进制转8进制:

复制代码 代码如下:
perl -ne 'printf "%o\n",$_'

16进制转10进制:

复制代码 代码如下:
perl -ne 'print hex($_)."\n"'

8进制转10进制:

复制代码 代码如下:
perl -ne 'print oct($_)."\n"'

简易计算器

复制代码 代码如下:
perl -ne 'print eval($_)."\n"'

批量重命名文件
以下是在verycd网站下载的资料,现对其改名的例子:

复制代码 代码如下:
$ 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

$ ls
李斯傳奇 - 第001回.mp3
$ perl -MFile::Find -e 'find sub{ rename $_,$1.".mp3" if /(\d+)(.*)\.mp3$/;}, "." '
$ ls
001.mp3

$ ls
十二生肖妙品欣赏系列 01 子鼠精灵.pdf
$ perl -MFile::Find -e 'find sub{ rename $_,"$2$3".".pdf" if /(.*)\s(\d+)\s(.*)\.pdf$/;}, "." '
$ ls
01子鼠精灵.pdf

中文标点符号替换(中文在此占3个字符位)
女人当国$ ls
女人当国01:选秀入宫.mp3 女人当国16:“议政王”的奥妙.mp3

将'mp3'文件修改为:01.选秀入宫.mp3,像如下格式:
perl -MFile::Find -E 'find sub{ rename $_,"$1.$3".".mp3" if /(\d{2})([^u4E00-u9FA5]{3})(.*).mp3$/;}, "." '
女人当国$ ls
01.选秀入宫.mp3 13.京城风云动.mp3

...
秦琼:“战将”最终成“门神”(上).mp3
将'“”)'引号去掉
perl -MFile::Find -E 'find sub{ my $o=$_; s/“|”|)//g;rename $o,$_}, "." '

秦琼:战将最终成门神(上).mp3

将':('替换为'.'
perl -MFile::Find -E 'find sub{ my $o=$_; s/:|(|,/\./g;rename $o,$_}, "." '
秦琼.战将最终成门神.上.mp3

在数字编号后加入'.'
01石头里生出美猴王.mp3
perl -MFile::Find -E 'find sub{my $o=$_;s/(^\d+)/$1\./;rename $o,$_},"."'
01.石头里生出美猴王.mp3

将前置中文字符去掉
独立书店_01.台北.书店之城.1.mp3
perl -MFile::Find -E 'find sub{ my $o=$_; s/([^u4E00-u9FA5]{12}_)//g;rename $o,$_}, "." '
01.台北.书店之城.1.mp3

在命令行下查看当前目录下的目录
用于列出当前目录的目录:一级目录和所有目录。
使用内置的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 '@a=File::Find::Rule->directory->in(".");foreach(@a){say unless(/\/|\./)};'
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

只是使用File::Find模块的find子例程来实现目录遍历,对符合条件的文件作重命名而已。

统计相关的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{$_}"} }'

查看ip尾数为9且端口为80的所有连接,按连接数从多到少排列,显示前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

查看ip尾数为9且端口为80的所有连接,统计连接状态信息

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

统计一文本文件有多少行:

复制代码 代码如下:
perl -le 'open FILE, "file_name"; @_=<FILE>; 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

wc -l file_name
cat file_name |wc -l
more file_name |wc -l

注:经对一个包含六百多万行的文件进行处理,发现'wc -l'的效率是最好的。

其他
启动交互式perl:

复制代码 代码如下:
perl -de 1

查看包含路径的内容:

复制代码 代码如下:
perl -le 'print for @INC'

perl 生成随机密码
主要还是借用'rand'函数来实现。

复制代码 代码如下:
$random = int( rand( $Y-$X+1 ) ) + $X;

下面的示例将会输出25-75之间的随机数:

复制代码 代码如下:
$random = int( rand(51)) + 25;
print "$random\n";

The rand function returns a fractional number, from (and including) 0 up to (but not including) its argument. We give it an argument of 51 to get a number that can be 0 or more, but never 51 or more. We take the integer portion of this to get a number from 0 to 50, inclusive (50.99999.... will be turned
into 50 by int). We then add 25 to it to get a number from 25 to 75, inclusive.

从数组中随机返回元素

复制代码 代码如下:
$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位长度的密码

复制代码 代码如下:
use strict;
use warnings;
my @chars=("a".."z",0..9);

my $password="";
foreach(1..42){
my $char=$chars[int(rand(@chars))];
$char=uc($char) if rand() <0.5;
$password.=$char;
}

print $password . "\n";

-------------------------------
my @chars = ('0'..'9', 'a'..'z', 'A'..'Z');
my $passwd =
join '',
map $chars[rand(@chars)],
1..42;

调用String::Random模块来实现:

复制代码 代码如下:
use strict;
use warnings;
use String::Random 'random_regex';

print random_regex('[a-zA-Z]{42}'), "\n";

使用perl in one line来完成:

复制代码 代码如下:
perl -le "print map { ('a'..'z', 'A'..'Z', '0'..'9')[rand 62] } 1..42"

perl -le 'print map { ("a".."z")[rand 26] } 1..8'

perl -le 'print map { ("a".."z", 0..9)[rand 36] } 1..8'

perl -le 'print map { (q(a)..q(z))[rand(26)] } 1 .. 10'

相关问题参考:
--------------------------------------------------------------------------
Perl one-liner with single quote-perl命令行里处理单引号
示例如下:

复制代码 代码如下:
echo "a,b" | perl -F',' -lane 'print $F[0];'
'a'

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

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

以上三种方法都不能达到预期,可以使用'-w'参数来进行控制,但其在变量环境无法使用。

复制代码 代码如下:
perl -lwe "print q( i'am );"
i'am

perl -lwe "$b=q( didn't ); print $b"

这里却没有了输出。

解决办法:
1、使用'\''转义。

复制代码 代码如下:
echo "a,b" | perl -F',' -lane 'print "'\''$F[0]'\''";'
'a'

2、使用'''的ASCII码

复制代码 代码如下:
echo "a,b" | perl -F',' -lane 'print "$F[0]\047";'
a'

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

声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

相关文章