Perl命令行应用介绍
2009-12-01 13:44:29 阿炯

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 脚本语法,而不执行脚本。

-C [number/list]   启用列出的Unicode功能

命令行-C开关通过后面相应的参数指定应用到标准文件句柄的编码方式:
I    1    STDIN假定为用UTF-8
O    2    STDOUT将会用UTF-8
E    4    STDERR将会用UTF-8
S    7    I+O+E
i    8    输入数据流的默认PerlIO层使用UTF-8
o    16    输出数据流的默认PerlIO层使用UTF-8
D    24    i+o

-d[:debugger]
对脚本打开 Perl调试器。

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

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

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

-h
打印 Perl 的命令选项列表。

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

-I directory
指定 @INC/#include 目录。与 -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。

-t
允许污染警告

-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://www.freeoa.net"'

-M模块名和use 模块名一样。有些模块有默认的模块导入,如果你不想导入它们,你可以使用-m。-m模块名和 use module() 一样,关闭了默认的导入。例如下面这个例子,因为 head 函数是默认导入,而使用-m 时就不会执行,结果是没有输出。
$ perl -mLWP::Simple -e 'print head "http://www.freeoa.net"'

-m 和 -M 有很多方便的语法来帮助你使用它们,你可以在 = 后面列出对 use 的各种参数。

$ perl -MCGI=:standard -e 'print header'
在这里,CGI.pm 的 :standard 被引入,header 函数因此可以使用。要引入多个参数可以通过使用引号和逗号。

$ perl -MCGI='header,start_html' -e 'print header,start_html'
这里我们引入了 header 和 start_html 函数。

--------------------
Implicit Loops
-n 和 -p 增加了循环的功能,使你可以一行一行来处理文件。
$ perl -n -e 'some code' file1

这与下面的程序一样.
LINE:
while () {
# your code goes here
}
注意:打开命令行里的文件,一行行的读取,每一行将缺省保存在 $_。

$ perl -n -e 'print "$. - $_"' file
上面的这一行可以写成 LINE: while () { print ”$. – $_” } 输出当前行数 $. 和当前行 $_,-p可以让上面的程序变得更容易,-p 会输出 $_ 的内容,就像这样:
while () {
# your code goes here
} continue {
print or die "-p destination: $!\n";
}

continue 在这里保证 print 在每次循环都会被调用。使用 -p,我们的打印行数程序可以改为
$ perl -p -e '$_ = "$. - $_"' filename

这种情况下我们就不需要要明确地调用 print 函数了,因为 -p 选项已经调用了它。注意,LINE: 标签可以让我们直接跳到下一个输入记录,而不管你进入了多少层循环,使用 next LINE。
$ perl -n -e 'next LINE unless /pattern/; print $_'

当然也可以这样写:
$ perl -n -e 'print unless /pattern/'

在更复杂的情况里,next LINE可以让你的代码更容易理解。如果想在循环的前后做些处理,可以使用 BEGIN或END block,下面的这一行代码可以计算 text 文件里的字数:
$ perl -ne 'END { print $t } @w = /(\w+)/g; $t += @w' file.txt

每一行所有匹配的字放入数组 @w,然后把 @w 的元素数目递加到$t,END block 里的 print 最后输出文件总字数。

还有两个参数可以让这个程序变得更简单,-a 打开自动分离 (split) 模式,空格是缺省的分离号,输入根据分离号被分离然后放入缺省数组 @F。由此,我们可以把上面的程序改写为:
$ perl -ane 'END {print $x} $x += @F' file.txt

你也可以通过 -F 把缺省的分离号改为你想要的.例如把分离号定为非字符:
$ perl -F'\W' -ane 'END {print $x} $x += @F' file.txt

下面通过 Unix password 文件来介绍一个复杂的例子。Unix password 是文本文件,每一行是一个用户记录,由冒号 ':'分离。第6列是用户的登录 shell 路径,我们可以得出每一个不同 shell 路径被多少个用户使用:
$ perl -F':' -ane 'chomp($F[6]); $s{$F[6]}++; END{print"$_:$s{$_}n" for keys %s}' /etc/passwd
$ perl -F':' -alne '$s{$F[6]}++;' -e 'END { foreach (keys %s){chomp($_);print "$_ \: $s{$_}"} }' /etc/passwd
有如下输出:
/usr/sbin/nologin : 3
/bin/sh : 18
/bin/sync : 1
/bin/bash : 2
/bin/false : 9

----------------
数据分隔符
我以前的文章里提到过 $/ 和 $\ 作为输入,输出分隔号。$/ 用来分隔从文件句柄里读出的数据,缺省 $/ 分隔号是 \n,这样每次从文件句柄里就会一行行的读取。$\ 缺省是空字符,用来自动加到要 print 的数据尾端。这就是为什么很多时候 print 都要在末尾加上 \n,$/ 和 $\ 可与 -n -p 一起使用。在命令行上相对应为 -0 (零) 和 -l (这是 L)。-0 后面可以跟一个16 进制或8进制数值,这个值用来赋给 $/。-00 打开段落模式,-0777 打开slurp 模式(即可以一次把整个文件读入),这与把 $/ 设为空字符和 undef 一样效果。

单独使用 -l 有两个效果,第一自动 chomp 输入分隔号,第二 把$/ 值付给 $\ (这样 print 的时候就会自动在末尾加 \n)我个人常常使用 -l 参数,用来给每一个输出加 \n,例如:
$ perl -le 'print "Hello World"'

-------------
原位编辑
使用已有的参数我们可以写出很有效的命令行程序. 常见的Unix I/O 重定向:
$ perl -pe 'some code' output.txt

这个程序从 input.txt 读取数据,然后做一些处理再输出到 output.txt. 你当然也可以把输出重定向到同一个文件里。上面的程序可以通过 -i 参数做的更简单些。-i 把源文件更名然后从这个更名的源文件里读取,最后把处理后的数据写入源文件。如果 -i 后跟有其他字符串,这个字符串与源文件名合成后来生成一个新的文件名,此文件会被用来储存原始文件以免被 -i 参数覆盖。

这个例子把所有php字符替换为perl:
$ perl -i -pe 's/\bPHP\b/Perl/g' file.txt

程序读取文件的每一行,然后替换字符,处理后的数据重新写入(即覆盖) 源文件. 如果不想覆盖源文件,可以使用$perl -i.bak -pe 's/\bPHP\b/Perl/g' file.txt

这里处理过的数据写入 file.txt ,file.txt.bak 是源文件的备份。

----------------------------
打开Perl的taint模式
1、该程序的输入数据来自外部数据源。
2、该程序所调用sub-shell或者函数影响到该程序之外其它东西。

可以用“-T”开关来打开Perl的taint模式。当打开taint模式时,Perl就会进行执行检查以确保你的数据未被taint,如果不安全的使用了被taint的数据,就会发出严重错误。为了使你的数据不被taint,执行正则表达式来匹配数据并提取匹配部分。这样就必须描述出你所期望的数据的内容以及格式,并只接受符合这一要求的数据。

假设期望收到一个单词字符(word characters,即字母数字以及下划线),那么下面的代码通过一个正则表达式(它只通过全部由单词字符组成字符串)会“蒸馏出”你的数据来:
if ($data =~ /^(\w+)$/) {
$data = $1;
} else {
die ”Error: tainted data found: $data\n”;
}

----------------------
Perl命令行调试
缺省的Perl调试器就是perl解释器本身,另外还有图形界面的调试器。图形界面的调试器推荐ptkdb,这里不再进行介绍,下载安装以后用两次便会。所以这里主要介绍一下缺省的命令行调试器的用法,一般的调试,用下面这些命令已经足够了,这些命令说明也来自网上整理而成。

用 -d 命令行选项启动Perl解释器,例如:
perl -d test.pl 即进入Perl调试器的交互界面。

调试命令列表如下:(所有命令都在调试提示符下顶格输入,命令大小写有关)
h:显示调试器的帮助信息。
|h:以分页形式显示调试器的帮助信息。
h h:显示一个压缩的帮助信息。
h 调试命令:显示某个调试命令的帮助。
p 表达式:显示变量或表达式的值,不显示复杂变量嵌入的结构和数据。
x 表达式:显示变量或表达式的值,对较为复杂的变量,以一种可读形式显示嵌入的结构和数据。
V 包名 变量名列表:显示指定包内的所有(或部分)变量的值。(缺省的包名为 main)
X 变量名列表:显示当前包内所有(或部分)变量的值。

注:V、X命令中的变量名列表以空格分隔且变量名前应去掉$、@或%。

T:程序的调用栈回退一级。
s 表达式:单步执行,进入子函数。(step into)如果提供一个表达式并且表达式中包括函数调用,则单步进入该函数内。
n 表达式:单步执行,越过子函数。(step over)
c 行号/函数名:执行到某一行或某一个函数。
l:显示未执行的一窗(一屏)文件内容。
l min-max:显示第min到第max行的文件内容。
l 行号:显示指定行的内容。
l 函数名:显示指定函数的一窗(一屏)文件内容。
w 行号:显示某行周围一窗(一屏)文件内容。
f 文件名:切换到另一个文件。
/模式:在当前文件中向前(文件尾)查找匹配的字符串。
?模式:在当前文件中向后(文件头)查找匹配的字符串。
L:显示所有断点和附加操作。
S 模式:显示匹配(或不匹配,在模式前加!)的函数名。
t:切换跟踪模式。
t 表达式:跟踪执行表达式过程。
b 行号 条件:在某一行设置一个断点,当程序执行到该行并且条件满足时,产生中断。
b 函数名 条件:在某函数上设置一个断点,当程序执行到该函数并且条件满足时,产生中断。
b load 文件名:在某个文件的第一个可执行语句上设置一个断点。
d 行号:删除某一行的断点。
D:删除所有断点。
a 行号 命令:给程序的某一行加一个附加操作。在执行该行语句前先执行附加的操作。
A:删除所有已安装的附加操作。
W 表达式:增加一个监视项。
W:删除所有监视项。
O 选项名?:查询调试器可选项的值。
O 选项名=选项值:设置调试器可选项的值。
lt Perl语句:设置一个操作显示调试提示符前执行的操作。
ltlt Perl语句:增加一个显示调试提示符前执行的操作。
gt Perl语句:设置一个离开调试提示符(转入运行态)时执行的操作。
gtgt Perl语句:增加一个离开调试提示符(转入运行态)时执行的操作。
{ 调试命令:设置一个操作显示调试提示符前执行的操作。
{{ 调试命令:设置一个操作显示调试提示符前执行的操作。
注:上述Perl语句和调试命令均可输入多行,行尾以\转义。
!number:重新执行以前第number次执行的调试命令。
!-number:重新执行现在以前number次执行的调试命令。
!模式:重新执行以前执行过的与模式匹配的调试命令。
!!命令:不退出调试器执行一个shell命令。
H-number:显示以前执行的number条调试命令。如果省略number,则显示所有执行过的调试命令。
R:重新启动正在调试的程序。
q或^D:退出调试器。
|调试命令:将调试命令的输出分页显示。
||调试命令:类似|调试命令,适于有大量输出的调试命令,例如:|V main。
= 别名 值:给某个调试命令一个别名,例如:= quit q。

所有未识别的命令:当作插入的一条Perl语句执行(使用eval)。
Perl调试器的功能还有很多,可以设置很多选项来定制调试器的环境,它本身也是用Perl开发的,并且Perl发布中还有接口让你能开发其它的Perl调试器。如果要用Perl开发大的项目,有必要详细了解这些细节。使用调试器和设置调试器选项的例子请参考Perl发布中关于perldebug的文档。

-------------
更多信息
Perl有大量的命令行参数,这篇文章只是列举了最有用的一小部分,更详细的信息请参考“perlrun” 文档。

-------------------
命令行的运用
用perl做命令行的一些简单的介绍,来替代sed、awk之类的软件。

Perl作为命令行实用程序,可以度参考ibm的这篇文章。作者提到的很重要的一点是:有经验的程序员不应回避快速而又难看的解决方案。

-------------------------
命令行参数ARGV

程序名:$0
$0表示当前正在运行的Perl脚本名,有3种情况:
如果执行方式为perl x.pl,则$0的值为x.pl而非perl命令本身
如果执行方式为./x.pl,则$0的值为./x.pl
如果执行的是perl -e或perl -E一行式perl程序,则$0的值为-e或-E

perl将其命令行的参数列表放进@ARGV中。既然是数组,就可以访问($ARGV[n])、遍历,甚至修改数组元素。ARGV数组分三种情况:
perl x.pl a b c方式运行时,脚本名x.pl之后的a b c才会被收集到ARGV数组
./x.pl a b c方式运行时,a b c才会被收集到ARGV数组
perl -e 'xxxxx' a b c方式运行时,a b c才会被收集到ARGV数组

ARGV数组索引跟perl数据一样是从0开始计算,索引0位从脚本名(perl程序名)之后的参数开始计算;默认这些命令行参数是perl程序的数据输入源,也就是perl会依次将它们当作文件进行读取。参数是有序的,读取的时候也是有序的;需要区分ARGV变量和ARGV数组:
$ARGV表示命令行参数代表的文件列表中,当前被处理的文件名
@ARGV表示命令行参数数组
$ARGV[n]:表示命令行参数数组的元素
ARGV:表示<>当前正在处理的文件句柄

例如,freeoat.pl的内容如下:
print '$ARGV[0] ---> ',$ARGV[0],"\n",'$ARGV[1] ---> ',$ARGV[1],"\n",'$ARGV[2] ---> ',$ARGV[2],"\n",'$ARGV[3] ---> ',$ARGV[3],"\n",'$ARGV[4] ---> ',$ARGV[4],"\n";

> ./freeoat.pl -w a b c d
$ARGV[0] ---> -w
$ARGV[1] ---> a
$ARGV[2] ---> b
$ARGV[3] ---> c
$ARGV[4] ---> d

因为是数组所以可以修改数组,比如强制指定元素:
@ARGV=qw(first second third);
print '$ARGV[0] ---> ',$ARGV[0],"\n",'$ARGV[1] ---> ',$ARGV[1],"\n",'$ARGV[2] ---> ',$ARGV[2],"\n";

读取两个文件(fa.txt,fb.txt)的内容:
while(<>){
 print $_;
}

> ./freeoat.pl fa.txt fb.txt

如果想读取标准输入,只需使用"-"作为文件参数即可。

> echo -e "abcd\nefg" | ./freeoat.pl fa.txt - fb.txt

上面将按先后顺序读取fa.txt,标准输入(管道左边命令的输出内容),fb.txt。

-------------------------
将多个空白行缩减为单个空行

Replace multiple newlines with a single one with Perl Regular Expressions、

1.s/^\n\z//
输入是逐行读取的,所以永远不会得到超过一行的换行符。
perl -ne 's/^\n$//; print'
perl -ne 's/^\n\z//; print'
perl -ne 's/\A\n\z//; print'

perl -pe 's/^\n$//'

不需要/s开关,/s:将待匹配串视为单行。

2.不输出打印空行就更简单:
$(input) | perl -ne 'print if /\S/'

将输出除仅包含空白的行之外的所有行。

3.修改perl默认的行分隔符
输入是三个独立的行,带有-p选项的perl一次只处理一行,解决方法是告诉perl一次输入多行。一种方法是:
echo $'a\n\nb' | perl -pe 'BEGIN{$/=undef}; s/\n\n/\n/'

这里的$/是记录分隔符变量(系统默认),它告诉perl如何将输入流解析行为。上面对它的处理相当于引入了/s修饰符。
perl -pe 's/^\n$//s' file.txt

cat file.txt | perl -pe 'BEGIN{$/=undef}; s/\n{3}/\n/gs'
等同于
perl -0777 -pe 's/\n{3}/\n/gs' file.txt

每段落增加了5个换行符
perl -00 -pe '$_ .= "\n"x5' file.txt

-pe0 与 -pe '' 的结果是一样的。以段落模式对文本文件进行输出:
perl -00 -pe0 file.txt

-------------------------
从Shell环境中传入变量参数(-s)

for d in 1 2 3; do perl -se 'print "$sp"' -- -sp=$d; done

perl -sE 'say $foo' -- -foo=$MYVAR

perl -se 'print "$foo\n" if $foo' -- -foo=$MYVAR

perl -le 'print shift' foo


-------------------------
Perl单行命令示例
我们先看看perl如何接收用户的参数。如下,Dumper模块不用理会,只是它会给数据结构打印出来,shell给接收到的参数都放到了@ARGV这个数组。
perl -MData::Dumper -e 'print Dumper \@ARGV' a b -w
$VAR1 = [
'a',
'b',
'-w'
];

如上,perl可以直接接收到shell命令行的参数。“-e”后的任何内容并将它当作脚本来运行。“-M”参数表示获取其后的任何内容并将该内容作为模块导入,类似于正规脚本中的“use ModuleName”。我们可以看到象所有的 Perl 程序一样,只有程序的最后一行不需要以 ; 结尾。

注:-e在单行命令中非常的重要,做单行命令时一定要加入在使用perl的单行命令时要注意使用”,不要使用"",其实sed和awk也是一样,当然这只是一个建议,看下面的例子就能明白:
perl -e 'print "$$\n"'
5719

'$$'在perl中表示当前的pid,如果使用的是单引号,其中还可以放双引号,还有变量,重要的是,这些变量不用担心被shell转义。

perl -pi -e 's/aaa/bbb/' filename
修改当前file文件中的文件,不生成中间文件,速度很快.记住 -i 开关,因为它让你原地编辑文件。

perl -ne 'print if /^int/' filename
象grep一样过滤文件中需要的内容。这个地方,使用了-n,所以一次是做一行的操作,直到整个文件读完。另外,在管道时,-n也会一样,来遍历管道送过来的内容。

perl -n -e 'print "$. - $_"' filename
这个例子中的,没用-ne,只是命令写成了-n -e,其实一样,这个例子中,是给当前文件中的内容都加一个行号打印出来.注:$.表示当前行号。

perl -pe '$_ = "$. $_"' filename
这个其实和上面一样,分别只是使用了-p替换了-n,这个有个什么好处啦,别的地方都一样,但-p按行来遍历完文件后,会给$_打印出来。相当于awk分割域(awk‘{i = NF – 1; print $1 + $i}’)。

perl -lane 'print $F[0] + $F[-2]'
这个神奇的地方在于-a,使用-a后.因为-n分行读进来,然后-a给数据分割成@F的数组。

perl -ne 'print if /^START$/ .. /^END$/'
打印正则中从$start到$end的地方

perl -ne 'print if $. >= 15; exit if $. >= 17;'
有效地打印数字范围中的行

perl -p -i.bak -e 's/\bfoo\b/bar/g' *.c
原地修改 -i 开关的神奇之处在于它对 @ARGV 中的每个文件都用该脚本对该文件输出所产生的文件版本进行替代。

perl -ne 'print scalar reverse $_' test
给文件中的内容反向排序,比如文件中有fukai,就会变成iakuf.

替换
将所有C程序中的foo替换成bar,旧文件备份成.bak
perl -p -i.bak -e 's/\bfoo\b/bar/g' *.c

很强大的功能,特别是在大程序中做重构。记得只有在UltraEdit用过,如果你不想备份,就直接写成 perl -p -i -e 或者更简单 perl -pie

将每个文件中出现的数值都加一
perl -i.bak -pe 's/(\d+)/ 1 + $1 /ge' file1 file2 ....

将换行符\r\n替换成\n
perl -i -p -e 's/\r\n/\n/g' file
同dos2unix命令。

将换行符\n替换成\r\n
perl -i -pe 's/\n/\r\n/g' file
同unix2dos命令。

取出文件的一部分
显示字段0-4和字段6,字段的分隔符是空格
perl -lane 'print "@F[0..4] $F[6]"' file
同 awk 'print $1, $2, $3, $4, $5, $7',参数名称lane也很好记。

如果字段分隔符不是空格而是冒号,则用
perl -F: -lane 'print "@F[0..4]\n"' /etc/passwd

显示START和END之间的部分
perl -ne 'print if /^START$/ .. /^END$/' file

相反,不显示START和END之间的部分
perl -ne 'print unless /^START$/ .. /^END$/' file

显示开头50行:
perl -pe 'exit if $. > 50' file
同命令 head -n 50

不显示开头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
这个就是普通的grep命令了。

查找不含comment字符串的行:
perl -ne 'print unless /comment/' duptext
反向的grep,即grep -v。

查找包含comment或apple的行:
perl -ne 'print if /comment/ || /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(".");'

找出当前目录中大小最大的文件(对当前目录的文件按大小顺序列出)

将列出文件名及其大小
perl -MFile::Find -E 'find sub{say "$_:".int((-s $_)/(1024*1024))."MB"}, "." '

列出几个较大的文件,最后一个一定最大的文件
perl -MFile::Find -E 'find sub{$a{$_}=int((-s $_)/(1024*1024))}, ".";END{for(keys %a){state $o=$a{$_};if($a{$_}>$o){say "$_:$a{$_}";$o=$a{$_}};}}'
perl -MFile::Find -E 'find sub{$a{$_}=int((-s $_)/(1024*1024))}, ".";END{for(keys %a){state $o=$a{$_};if($a{$_}>$o){$f=$_;$s=$a{$_};$o=$a{$_}};}say "$f:$s"}'

如果用系统的'ls'指令,可如下操作:
常用:ls -lh
通过查看man手册,有如下两个选项可用:
-S sort  by file size
-r, --reverse reverse order while sorting

所有按大小排序的话,就应该是:
ls -Slhr

对目录下的文件进行大小写修改
$ 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{$_}"} }'


对文本文件中的IP地址排序,假设一批IPv4地址,按ip段、同段按最后一位从小到大的顺序排列,文件中的每行一个IP地址
perl -nl -MSocket -E 'chomp;push @aipn,unpack('N',inet_aton($_));END{say inet_ntoa(pack('N',$_)) foreach(sort @aipn)}' freeoaip.list


统计一文本文件有多少行:
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 v5.20;
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 v5.20;
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 v5.20;
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 'print "$F[0]\x27";'
a'

echo "a,b" | perl -F',' -lane '$sq="\047"; print "$sq$F[0]$sq";'
--------------------------------------------------------------------------
本站内扩展参考:

Perl单行应用详解

Perl one line command 中文简介


--------------------------------------------------------------------------
Perl Interpreter Options(尽量保持英文原文)

A single-character options may be combined. This is useful when invoking a script using the #! construct which only allows only a single argument. Example:
#!/usr/bin/perl -spi.bak # same as -s -p -i.bak
...

Perl options include:

-0digits

specifies the record separator ($/) as an octal number. If there are no digits, the null character is the separator. Other switches may precede or follow the digits. For example, if you have a version of find which can print filenames terminated by the null character, you can say this:
find . -name '*.bak' -print0 | perl -n0e unlink

The special value 00 will cause Perl to slurp files in paragraph mode. The value 0777 will cause Perl to slurp files whole since there is no legal character with that value.

-a

turns on autosplit mode when used with a -n or -p. An implicit split command to the @F array is done as the first thing inside the implicit while loop produced by the -n or -p.
perl -ane 'print pop(@F), "\n";'

is equivalent to
while (<>){
    @F = split(' ');
    print pop(@F), "\n";
}

-c

causes perl to check the syntax of the script and then exit without executing it.

-d

runs the script under the perl debugger. See the section on Debugging.

-Dnumber

sets debugging flags. To watch how it executes your script, use -D14. (This only works if debugging is compiled into your perl.) Another nice value is -D1024, which lists your compiled syntax tree. And -D512 displays compiled regular expressions.

-e commandline

may be used to enter one line of script. Multiple -e commands may be given to build up a multi-line script. If -e is given, perl will not look for a script filename in the argument list.

-iextension

specifies that files processed by the <> construct are to be edited in-place. It does this by renaming the input file, opening the output file by the same name, and selecting that output file as the default for print statements. The extension, if supplied, is added to the name of the old file to make a backup copy. If no extension is supplied, no backup is made. Saying "perl -p -i.bak -e "s/foo/bar/;" ... " is the same as using the script:
#!/usr/bin/perl -pi.bak
s/foo/bar/;

which is equivalent to
#!/usr/bin/perl
while (<>) {
    if ($ARGV ne $oldargv) {
        rename($ARGV, $ARGV . '.bak');
        open(ARGVOUT, ">$ARGV");
        select(ARGVOUT);
        $oldargv = $ARGV;
    }
    s/foo/bar/;
}continue{
    print; # this prints to original filename
}
select(STDOUT);

except that the -i form doesn't need to compare $ARGV to $oldargv to know when the filename has changed. It does, however, use ARGVOUT for the selected filehandle. Note that STDOUT is restored as the default output filehandle after the loop.

You can use eof to locate the end of each input file, in case you want to append to each file, or reset line numbering (see example under eof).

-Idirectory

may be used in conjunction with -P to tell the C preprocessor where to look for include files. By default /usr/include and /usr/lib/perl are searched.

-loctnum

enables automatic line-ending processing. It has two effects: first, it automatically chops the line terminator when used with -n or -p , and second, it assigns $\ to have the value of octnum so that any print statements will have that line terminator added back on. If octnum is omitted, sets $\ to the current value of $/. For instance, to trim lines to 80 columns:
perl -lpe 'substr($_, 80) = ""'

Note that the assignment $\ = $/ is done when the switch is processed, so the input record separator can be different than the output record separator if the -l switch is followed by a -0 switch:
gnufind / -print0 | perl -ln0e 'print "found $_" if -p'

This sets $\ to newline and then sets $/ to the null character.

-n

causes perl to assume the following loop around your script, which makes it iterate over filename arguments somewhat like "sed -n" or awk:
while(<>){
... # your script goes here
}

Note that the lines are not printed by default. See -p to have lines printed. Here is an efficient way to delete all files older than a week:
gfind . -mtime +7 -print | perl -nle 'unlink;'

This is faster than using the -exec switch of find because you don't have to start a process on every filename found.

-p

causes perl to assume the following loop around your script, which makes it iterate over filename arguments somewhat like sed:
while (<>) {
...        # your script goes here
}continue{
    print;
}

Note that the lines are printed automatically. To suppress printing use the -n switch. A -p overrides a -n switch.

-P

causes your script to be run through the C preprocessor before compilation by perl. (Since both comments and cpp directives begin with the # character, you should avoid starting comments with any words recognized by the C preprocessor such as "if", "else" or "define".)

-s

enables some rudimentary switch parsing for switches on the command line after the script name but before any filename arguments (or before a --). Any switch found there is removed from @ARGV and sets the corresponding variable in the perl script. The following script prints "true" if and only if the script is invoked with a -xyz switch.
#!/usr/bin/perl -s
if ($xyz) { print "true\n"; }

-S

makes perl use the PATH environment variable to search for the script (unless the name of the script starts with a slash). Typically this is used to emulate #! startup on machines that don't support #!, in the following manner:
#!/usr/bin/perl
eval "exec /usr/bin/perl -S $0 $*"
    if $running_under_some_shell;

The system ignores the first line and feeds the script to /bin/sh, which proceeds to try to execute the perl script as a shell script. The shell executes the second line as a normal shell command, and thus starts up the perl interpreter. On some systems $0 doesn't always contain the full pathname, so the -S tells perl to search for the script if necessary. After perl locates the script, it parses the lines and ignores them because the variable $running_under_some_shell is never true. A better construct than $* would be ${1+"$@"}, which handles embedded spaces and such in the filenames, but doesn't work if the script is being interpreted by csh. In order to start up sh rather than csh, some systems may have to replace the #! line with a line containing just a colon, which will be politely ignored by perl. Other systems can't control that, and need a totally devious construct that will work under any of csh, sh or perl, such as the following:
eval '(exit $?0)' && eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
& eval 'exec /usr/bin/perl -S $0 $argv:q' if 0;

-u

causes perl to dump core after compiling your script. You can then take this core dump and turn it into an executable file by using the undump program (not supplied). This speeds startup at the expense of some disk space (which you can minimize by stripping the executable). (Still, a "hello world" executable comes out to about 200K on my machine.) If you are going to run your executable as a set-id program then you should probably compile it using taintperl rather than normal perl. If you want to execute a portion of your script before dumping, use the dump operator instead. Note: availability of undump is platform specific and may not be available for a specific port of perl.

-U

allows perl to do unsafe operations. Currently the only "unsafe" operations are the unlinking of directories while running as superuser, and running setuid programs with fatal taint checks turned into warnings.

-v

prints the version and patchlevel of your perl executable.

-w

prints warnings about identifiers that are mentioned only once, and scalar variables that are used before being set. Also warns about redefined subroutines, and references to undefined filehandles or filehandles opened readonly that you are attempting to write on. Also warns you if you use == on values that don't look like numbers, and if your subroutines recurse more than 100 deep.

-xdirectory

tells perl that the script is embedded in a message. Leading garbage will be discarded until the first line that starts with #! and contains the string "perl". Any meaningful switches on that line will be applied (but only one group of switches, as with normal #! processing). If a directory name is specified, Perl will switch to that directory before running the script. The -x switch only controls the the disposal of leading garbage. The script must be terminated with __END__ if there is trailing garbage to be ignored (the script can process any or all of the trailing garbage via the DATA filehandle if desired).


Caution: Some UNIX systems will only read the first 32 characters of the #! line. So try to have your options either end before the 32nd position or start after the 32nd position. Placing the options after the 32nd position will help to make your scripts more portable because you will be bypassing one of the inconsistencies of UNIX.
注意:某些UNIX系统将只读取'#!'所在行的32个字符,所以试着让你的选择要么在第32个位置之前结束,要么在第32个位置之后开始。将选项放在第32个位置之后将有助于使脚本更具可移植性,就可以将绕过UNIX所在的发行版本的不一致性。


下表提供了与Perl一起使用的每个命令行选项的简短描述,其后将显示几个选项的示例。

Table Perl's Command Line Options
OptionDescription
-0Lets you specify the record separator ($/) as an octal number. For example, - 0055 will cause records to end on a dash. If no number is specified, records will end on null characters. The special value of 00 will place Perl into paragraph mode. And 0777 will force Perl to read the whole file in one shot because 0777 is not a legal character value. See "Example: Using the -0 option" for more information.
-aThis option must be used in conjunction with either the -n or -p option. Using the-a option will automatically feed input lines to the split function. The results of the split are placed into the @F variable. See "Example: Using the -n and -p Options" for more information.
-cThis option lets you check the syntax of your script without fully executing it. The BEGIN blocks, and use statements are still executed because they are needed by the compilation process.
-dThis option lets you start the Perl debugger. See Chapter 16, "Debugging Perl," for more information.
-DThis option lets you turn on different behaviors related to the debugging process. The following table shows you the sub-options that can be used. Please note, however, that not all releases of Perl can use this feature. I know that the hip port of Perl for Win32 can't. If your version of Perl does not have this option, you will see the message Recompile perl with -DDEBUGGING to use -D switch when you try it. If you want to watch your script as it executes, use -D14. Following is a list of the other values that you can use. You can add the numbers together to specify more than one behavior (such as 8+4+2 = 14) or you can use the letters.

 

1pTokenizing and Parsing
2sStack Snapshots
4lLabel Stack Processing
8tTrace Execution
16oOperator Node Construction
32cString/Numeric Conversions
64PPrint Preprocessor Command for -P
128mMemory Allocation
256fFormat Processing
512rRegular Expression Parsing
1024xSyntax Tree Dump
2048uTainting Checks
4096LMemory Leaks (not supported anymore)
8192HHash Dump -- usurps values()
16384XScratchpad Allocation
32768DCleaning Up
 
-eThis option lets you specify a single line of code on the command line. This line of code will be executed in lieu of a script file. You can use multiple -e options to create a multiple line program - although given the probability of a typing mistake, I'd create a script file instead. Semi-colons must be used to end Perl statements just like a normal script.
-FThis option modifies the behavior of the-a option. It lets you change the regular expression that is used to split the input lines. For example, -F /:+/ will split the input line whenever one or more colons are found. The slashes are optional; they simply delimit the pattern if they are there. I use them for their aesthetic value.
-iThis option lets you edit files in-place. It is used in conjunction with the -n or -p option. See "Example: Using the -i option" for more information.
-IThis option is used in conjunction with the-P option. It tells the C preprocessor where to look for include files. The default search directories include /usr/include and /usr/lib/Perl.
-lThis option turns on line-ending processing. It can be used to set the output line terminator variable ($/) by specifying an octal value. See "Example: Using the -0 option" for an example of using octal numbers. If no octal number is specified, the output line terminator is set equal to the input line terminator (such as $\ = $/;).
-nThis option places a loop around your script. It will automatically read a line from the diamond operator and then execute the script. It is most often used with the -e option. See "Examples: Using the -n and -p Options" for more information.
-pThis option places a loop around your script. It will automatically read a line from the diamond operator, execute the script, and then print $_. It is most often used with the -e option. See "Examples: Using the -n and -p Options" for more information.
-PThis option will invoke the C preprocessor before compiling your script. This might be useful if you have some C programming experience and would like to use the #include and #define facility. The C preprocessor can also be used for conditional compilation. Use the -I option to tell Perl where to find include files.
-sThis option lets you define custom switches for your script. See "Examples: Using the -s option" for more information.
-SThis option makes Perl search for the script file using the PATH environment variable. It's mostly used with UNIX systems that don't support the #! line. The docs/perlrun.htm documentation file that comes with your Perl distribution has more information about this option.
-TThis UNIX-based option turns on taint checking. Normally, these checks are only done when runningsetuid or setgid. The docs/perlsec.htm documentation file that comes with your Perl distribution has more information about this option.
-uThis UNIX-based option will cause Perl to dump core after compiling your script. See the Perl documentation that came with your Perl distribution for more information.
-UThis UNIX-based option will let Perl do unsafe operations. Its use is beyond the scope of this book.
-vThis option will display the version and patchlevel of your Perl executable.
-wThis option prints warnings about unsafe programming practices. See Chapter 16, "Debugging Perl," for more information.
-xThis option will let you extract a Perl script from the middle of a file. This feature comes in handy when someone has sent you a script via e-mail. Perl will scan the input file looking for a #! line that contains the word "perl". When it is found, it will execute the script until the __END__ token is found. If a directory name is specified after the -x option, Perl will switch to that directory before executing the script.


如上所述,Perl有相当多的命令行选项。它们中的大多数都是为了可以在不需要创建文本文件来保存脚本的情况下做有用的事情。如果您是系统管理员,那么这些选项将使工作效率更高。将能够快速准确地操作文件和数据。如果想创建应用程序或更复杂的程序,除了-w和-d之外不需要这些选项。

The rest of the chapter is devoted to demonstrating the -0, -n, -p, -i, and -s options.

Example: Using the -0 Option

The -0 option will let you change the record separator. This is useful if your records are separated by something other than a newline. Let's use the example of input records separated by a dash instead of a newline. First, you need to find out the octal value of the dash character. The easy way to do this is covert from the decimal value which will be displayed if you run the following command line.

$ perl -e "print ord('-');"

This program will display 45. Converting 45 into octal results in 55. Next, you'll need an input file to practice with.

伪代码
Set the record separator to be a dash using the #! switch setting method.
Open a file for input.
Read all of the records into the @lines array. One element in @lines will be one record.
Close the file.
Iterate over the @lines array and print each element.

$ more z.dat
Veterinarian-Orthopedist-Dentist-FreeOA-

$ more z1.pl
#!/usr/bin/perl
$/ = "-";
open(FILE, "<z.dat");
my @lines = <FILE>;
close(FILE);
print("$_\n") for(@lines);

$ more z2.pl
#!/usr/bin/perl -0055
open(FILE, "<z.dat");
my @lines = <FILE>;
close(FILE);
print("$_\n") for(@lines);

$ perl z.pl
Veterinarian-
Orthopedist-
Dentist-
FreeOA-

单行版本

$ perl -0055 -E 'open(FILE, "<","z.dat"); @lines = <FILE>; close(FILE); say for(@lines)'

$ perl -E '$/="-";open(FILE, "<","z.dat"); @lines = <FILE>; close(FILE); say for(@lines)'

$ perl -0055 -E '@lines=<>; say for(@lines)' z.dat


Example: Using the -n and -p Options

The -n and -p options wrap your script inside loops. Before looking at specific examples, let's see what the loops look like and how they are changed by the -a and -F options.

The -n option causes Perl to execute your script inside the following loop:
while (<>) {
    # your script
}

The -p option uses the same loop, but adds a continue block so that $_ will be printed every time through the loop. If both -n and -p are specified on the command line, the -p option will take precedence. The loop looks like this:
while (<>) {
    # your script
} continue {
    print;
}

The -a option adds a split() function call to the beginning of each iteration of the loop. So that the loop looks like this:
while (<>) {
    @F = split(/ /);
    # your script
}

The -F option lets you split on something besides the space character. If you used -F/|+/ on the command line, the loop would look like this:
while (<>) {
    @F = split(/|+/);
    # your script
}

You can use BEGIN and END blocks if you need to specify some initialization or cleanup code. The initialization section might be used to create objects or to open log files. The cleanup section can be used to display statistics or close files. For example,
BEGIN {
    # initialization section
    $count = 0;
}
while (<>) {
    # your script
}
END {
    # cleanup section
    print("The count was $count.\n");
}

Next, you'll see some examples of these options in action. Let's start with a command-line that simply displays each line of the input file - like the "type" command in DOS and UNIX.

The following examples use a data file called data.dat with the following lines:
David Veterinarian
John Orthopedist
Jeff Dentist

$ perl -p -e "1;" data.dat

This command line is equivalent to:
while (<>) {
    1;
} continue {
    print;
}

注意:The 1; statement was used to give Perl something to process. Otherwise, Perl would not have had any statements to execute.
 
And will display:
David Veterinarian
John Orthopedist
Jeff Dentist

How about just printing the first word of each line? You could use this command line:

$ perl -p -e "s/\s*(\w+).*/$1/;" test.dat

which is equivalent to:
while (<>) {
    s/\s*(\w+).*/$1/;
} continue {
    print;
}

And will display:
David
John
Jeff

If you have data files that store information in columns, you can pull out the second column of information like this:
$ perl -p -e "s/\s*.+\s(.+)\s*/$1\n/;" test.dat

which will display:
Veterinarian
Orthopedist
Dentist

You can use the -a option to get access to information stored in columns. For example, you could also display the second column like this:
$ perl -p -a -e "$_ = \"$F[1]\n\";" test.dat

which is equivalent to
while (<>) {
    @F = split(/ /);
    $_ = "$F[1]\n";
} continue {
    print;
}

Notice you need to escape the double-quotes in the above command-line. If you don't do this you get an error message.


Example: Using the -i Option

The -i option lets you modify files in-place. This means that Perl will automatically rename the input file and open the output file using the original name. You can force Perl to create a backup file by specifying a file extension for the backup file immediately after the -i. For example, -i.bak. If no extension is specified, no backup file will be kept.

One of the more popular uses for the -i option is to change sequences of characters. This kind of change normally requires 10 or more lines of code. However, using command line options you can do it like this:
$ perl -p -i.bak -e "s/harry/tom/g;" test.dat

This command line will change all occurrences of "harry" to "tom" in the test.dat file.

本段小结

-n选项用于将脚本放置在输入循环中。-p选项使用相同的循环,但在每次通过循环后打印$_变量。当希望将输入行拆分为@F数组时,将使用-a和-F选项。另一个非常有用的选项是-i,它允许原位编辑文件;当进行大量文本文件操作时,此选项非常好用。



该文章最后由 阿炯 于 2024-02-13 14:43:43 更新,目前是第 3 版。