Perl命令行应用程序详解
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 -1 digits -l 复制代码 代码如下: -m [-] module -M [-] module -M [-] module' -[mM] module = arg [,arg].. -m module 在执行 Perl 脚本之前执行 use 方法。 -M module -n -p -P -s -S -T -u -U -v -V -V:NAME -w -W -x directory -X 每一行将缺省保存在 $_,-p 和 -n 一样,但是还会打印 $_ 的内容。 请注意:-p 开关和 -n 开关的使用。当您想显式打印数据时,使用 -n 开关。-p 开关隐式地将 print $_ 语句插入到 -n 开关所产生的循环中。因此,-p 开关更适用于对文件进行的完全处理,而 -n 开关更适用于选择性文件处理,这样的处理只需打印特定数据。 安全网参数 -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 -e 'print "Hello Worldn"' 多个 -e 也可以同时使用,运行顺序根据它出现的位置。 复制代码 代码如下: $ perl -e 'print "Hello ";' -e 'print "Worldn"' 象所有的 Perl 程序一样,只有程序的最后一行不需要以 ; 结尾,你也可以用 -e 来引用模块,但 -M 让它变得更容易。 复制代码 代码如下: $ perl -MLWP::Simple -e 'print head "http://www.example.com"' -M模块名和use 模块名一样。有些模块有默认的模块导入,如果你不想导入它们,你可以使用-m。-m模块名和 use module() 一样,关闭了默认的导入。例如下面这个例子,因为 head 函数是默认导入,而使用-m 时就不会执行,结果是没有输出。 复制代码 代码如下: $ perl -mLWP::Simple -e 'print head "http://www.example.com"' -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 复制代码 代码如下: $ perl -n -e 'some code' file1 这与下面的程序一样. 复制代码 代码如下: while () { # your code goes here } 注意:打开命令行里的文件,一行行的读取,每一行将缺省保存在 $_。 复制代码 代码如下: $ perl -n -e 'print "$. - $_"' file 上面的这一行可以写成 LINE: while () { print ”$. C $_” } 输出当前行数 $. 和当前行 $_,-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 数据分隔符 单独使用 -l 有两个效果,第一自动 chomp 输入分隔号,第二 把$/ 值付给 $ (这样 print 的时候就会自动在末尾加 n)我个人常常使用 -l 参数,用来给每一个输出加 n,例如: 复制代码 代码如下: $ perl -le 'print "Hello World"' 原位编辑 复制代码 代码如下: $ perl -pe 'some code' output.txt 这个程序从 input.txt 读取数据,然后做一些处理再输出到 output.txt. 你当然也可以把输出重定向到同一个文件里。上面的程序可以通过 -i 参数做的更简单些。-i 把源文件更名然后从这个更名的源文件里读取,最后把处理后的数据写入源文件。如果 -i 后跟有其他字符串,这个字符串与源文件名合成后来生成一个新的文件名,此文件会被用来储存原始文件以免被 -i 参数覆盖。 这个例子把所有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”开关来打开Perl的taint模式。当打开taint模式时,Perl就会进行执行检查以确保你的数据未被taint,如果不安全的使用了被taint的数据,就会发出严重错误。为了使你的数据不被taint,执行正则表达式来匹配数据并提取匹配部分。这样你就必须描述出你所期望的数据的内容以及格式,并只接受符合这一要求的数据。 例如,假设你期望收到一个单词字符(word characters,即字母数字以及下划线),那么下面的代码通过一个正则表达式(它只通过全部由单词字符组成字符串)会“蒸馏出”你的数据来: 复制代码 代码如下: if ($data =~ /^(w+)$/) { $data = $1; } else { die ”Error: tainted data found: $datan”; } Perl命令行调试 用 -d 命令行选项启动Perl解释器,例如: 调试命令列表如下:(所有命令都在调试提示符下顶格输入,命令大小写有关) 注:V、X命令中的变量名列表以空格分隔且变量名前应去掉$、@或%。 T:程序的调用栈回退一级。 所有未识别的命令:当作插入的一条Perl语句执行。(使用eval) 更多信息 命令行的运用 Perl作为命令行实用程序,可以度参考ibm的这篇文章。作者提到的很重要的一点是:有经验的程序员不应回避快速而又难看的解决方案。 Perl单行命令示例 复制代码 代码如下: 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 C 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/bfoob/bar/g' *.c 原地修改 -i 开关的神奇之处在于它对 @ARGV 中的每个文件都用该脚本对该文件输出所产生的文件版本进行替代。 复制代码 代码如下: perl -ne 'print scalar reverse $_' test 给文件中的内容反向排序,比如文件中有fukai,就会变成iakuf. 替换 复制代码 代码如下: perl -p -i.bak -e 's/bfoob/bar/g' *.c 很强大的功能,特别是在大程序中做重构。记得只有在UltraEdit用过,如果你不想备份,就直接写成 perl -p -i -e 或者更简单 perl -pie 将每个文件中出现的数值都加一 复制代码 代码如下: perl -i.bak -pe 's/(d+)/ 1 + $1 /ge' file1 file2 .... 将换行符rn替换成n 复制代码 代码如下: perl -p -i -e 's/rn/n/g' file 同dos2unix命令。 将换行符n替换成rn 复制代码 代码如下: perl -pie 's/n/rn/g' file 同unix2dos命令。 取出文件的一部分 复制代码 代码如下: 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 搜索 复制代码 代码如下: 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了,语法比较复杂…… 计算 复制代码 代码如下: 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的反转) 数值计算 复制代码 代码如下: perl -ne 'printf "%xn",$_' 10进制转8进制: 复制代码 代码如下: perl -ne 'printf "%on",$_' 16进制转10进制: 复制代码 代码如下: perl -ne 'print hex($_)."n"' 8进制转10进制: 复制代码 代码如下: perl -ne 'print oct($_)."n"' 简易计算器 复制代码 代码如下: perl -ne 'print eval($_)."n"' 批量重命名文件 复制代码 代码如下: $ 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 $ ls 中文标点符号替换(中文在此占3个字符位) 将'mp3'文件修改为:01.选秀入宫.mp3,像如下格式: ... 秦琼:战将最终成门神(上).mp3 将':('替换为'.' 在数字编号后加入'.' 将前置中文字符去掉 在命令行下查看当前目录下的目录 复制代码 代码如下: 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连接情况 复制代码 代码如下: 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 注:经对一个包含六百多万行的文件进行处理,发现'wc -l'的效率是最好的。 其他 复制代码 代码如下: perl -de 1 查看包含路径的内容: 复制代码 代码如下: perl -le 'print for @INC' perl 生成随机密码 复制代码 代码如下: $random = int( rand( $Y-$X+1 ) ) + $X; 下面的示例将会输出25-75之间的随机数: 复制代码 代码如下: $random = int( rand(51)) + 25; print "$randomn"; 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 从数组中随机返回元素 复制代码 代码如下: $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=""; print $password . "n"; ------------------------------- 调用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' 相关问题参考: 复制代码 代码如下: echo "a,b" | perl -F',' -lane 'print $F[0];' 'a' echo "a,' -lane 'print qq('$F[0]');' echo "a,' -lane 'print q('$F[0]');' 以上三种方法都不能达到预期,可以使用'-w'参数来进行控制,但其在变量环境无法使用。 复制代码 代码如下: perl -lwe "print q( i'am );" i'am perl -lwe "$b=q( didn't ); print $b" 这里却没有了输出。 解决办法: 复制代码 代码如下: echo "a,' -lane 'print "'''$F[0]'''";' 'a' 2、使用'''的ASCII码 复制代码 代码如下: echo "a,' -lane 'print "$F[0] 47";' a' echo "a,' -lane '$sq="047"; print "$sq$F[0]$sq";' (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |