加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

perl-one-lines

发布时间:2020-12-16 00:25:59 所属栏目:大数据 来源:网络整理
导读:概要 本文包含一些perl中常见的命令行选项,也就是常说的one-liners。包含了-e,-n,-p,-M,-w选项,以及BEGIN和END。 1. 创建一个one-liner 我遇到的很多有天分的unix程序员都有一些必杀技。在遇到可以用Perl one-liner取代一个完整的脚本时,他们肯定不会
概要 本文包含一些perl中常见的命令行选项,也就是常说的one-liners。包含了-e,-n,-p,-M,-w选项,以及BEGIN和END。 1. 创建一个one-liner 我遇到的很多有天分的unix程序员都有一些必杀技。在遇到可以用Perl one-liner取代一个完整的脚本时,他们肯定不会写脚本。 -e开关允许我们在命令行中运行脚本。Code Listing1展示了一个简单的“Hello world”。 -----------------Code Listing1:Hello world-------------------------- prompt$ perl -e ’print "hello world!n"’ hello world! --------------------------------------------------------------------- Code Listing2,有一点复杂。从ls中获得输入,找到文件大小的字段,计算所有文件大小的总和。 -----------------Code Listing2:File Size Sum------------------------- prompt$ ls -lAF | perl -e ’while (<>) { next if /^dt/; $sum += (split)[4] } print "$sumn"’ 1185 --------------------------------------------------------------------- 在Code listing2中,我用了几个小技巧。通常情况下,我不会一次写好这样的东西。我一次写一点,确保我每次都会得到正确的结果。 在Code listing3中,我检查输出命令。 -----------------Code Listing3:ls output---------------------------- prompt$ ls -lAF total 32 drwxrwsr-x 2 jbay staff 512 Feb 21 09:34 adir/ -rw-rw-r-- 1 jbay staff 395 Feb 21 09:29 afile1 -rw-rw-r-- 1 jbay staff 423 Feb 21 09:29 afile2 -rw-rw-r-- 1 jbay staff 120 Feb 21 09:29 afile3 --------------------------------------------------------------------- 在Code Listing4中,ls的输出变成我的脚本的标准输入。ls的输出是每行一个。 我所期望的输出与Code Listing3是一样的。 -----------------Code Listing4:ls piped to perl--------------------- prompt$ ls -lAF | perl -e ’while (<>) { print $_ }’ total 32 drwxrwsr-x 2 jbay staff 512 Feb 21 09:34 adir/ -rw-rw-r-- 1 jbay staff 395 Feb 21 09:29 afile1 -rw-rw-r-- 1 jbay staff 423 Feb 21 09:29 afile2 -rw-rw-r-- 1 jbay staff 120 Feb 21 09:29 afile3 --------------------------------------------------------------------- 在Code List5中,我想跳过“total”行和文件夹,所以我想忽略以‘t’和‘d’开头的行,在显示结果之前我添加了“next”,来跳过以‘t’和‘d’开头的行。 -----------------Code Listing5:Skip Lines--------------------------- prompt$ ls -lAF | perl -e ’while (<>) { next if /^[dt]/; print $_; }’ -rw-rw-r-- 1 jbay staff 395 Feb 21 09:29 afile1 -rw-rw-r-- 1 jbay staff 423 Feb 21 09:29 afile2 -rw-rw-r-- 1 jbay staff 120 Feb 21 09:29 afile3 --------------------------------------------------------------------- 在我知道我的程序运行正确之后,我要获取每一行第五列的结果。这时,在Code Listing6中,输出上面与上面ls命令相同的结果-每一个文件的大小。 -----------------Code Listing6:Print File Size----------------------- prompt$ ls -lAF | perl -e ’while (<>) { next if /^[dt]/; print +(split)[4],"n" } ’ 395 423 120 --------------------------------------------------------------------- 最后,输出文件大小的总和,Code Listing7,累加文件大小总和,在程序最后输出。 -----------------Code Listing7:Sum File Size------------------------ prompt$ ls -lAF | perl -e ’while (<>) { next if /^[dt]/; $sum += (split)[4] } print "$sumn"’ 938 --------------------------------------------------------------------- 现在,我获得了在Code Listing2中的perl one-liner。 2.one-liner输入 perl程序能够从标准输入或者命令行参数(保存在@ARGV)中获得输入。 2.1标准输入 -----------------Code Listing8:Skip Comment------------------------- prompt$ cat afile | perl -e ’while (<>) { print unless /s+#/ }’ --------------------------------------------------------------------- “|”把cat命令的输出转换成perl程序的输入。钻石操作符“<>”从标准输入读取数据,所以这个程序从afile 读取数据,然后打印不匹配正则表达式s+#的行。 同样也可以通过shell重定向操作符<来重把文件内容重定向到perl的标准输入。 Code Listing9显示和前一个例子相同的输出。 -----------------Code Listing9:Input By Redirection----------------- prompt$ perl -e ’while (<>) { print unless /s+#/ }’ < afile --------------------------------------------------------------------- 不论如何,钻石操作符能够直接打开以及读取命令行指定文件的内容,所以不需要手动重定向文件内容。Code Listing10不用重定向, 并且得到Code Listing9相同的结果。 -----------------Code Listing10:Input------------------------------- prompt$ perl -e ’while (<>) { print unless /s+#/ }’ afile --------------------------------------------------------------------- 2.2命令行参数 可以通过@ARGV获得命令行参数,Code Listing11简单的打印@ARGV中的内容。 -----------------Code Listing11:Print The Command Line argument----- prompt$ perl -e ’print "@ARGVn"’ Foo Bar Bletch Foo Bar Bletch --------------------------------------------------------------------- 假如我有一个文件,他的内容是一些我想操作的文件的名字,每行一个。我可以同Code Listing12来获得这些文件的名字。 -----------------Code Listing12:The Filename in files.txt----------- prompt$ cat files.txt afile1 afile2 afile3 --------------------------------------------------------------------- Unix的xarg命令能够把他读取的数据转换成另一个命令的参数。我想把这些文件名转换成wc命令的参数以便于统计每个文件中行数。 在Code Listing中,xarg从标准输入读取数据-文件名,并把他们转换成wc的参数。 -----------------Code Listing13:Count Lines In Files---------------- prompt$ cat files.txt | xargs wc -l 54 afile1 54 afile2 54 afile3 162 total --------------------------------------------------------------------- Code Listing13和直接使用命令行参数的结果是一样的。如同Code Listing14 -----------------Code Listing1:Hello world-------------------------- prompt$ wc -l afile1 afile2 afile3 --------------------------------------------------------------------- 2.3使用find 在Code Line15中,我用perl one-liner和xarg来重新实现了find的“-type d”选项。find命令递归一个指定给定的文件夹,根据一个标准, 输出匹配的一组文件名。 -----------------Code Listing15:Using find-------------------------- prompt$ find . | xargs perl -e ’@ARGV = grep( -d $_,@ARGV); print "@ARGV"’ --------------------------------------------------------------------- 在Code Listing中,xarg接受文件名,并把他们作为参数传给perl one-liner。one-liner使用grep过滤文件,然后打印他们。 3 使用命令行开关 Perl命令行选项通过使用-e选项自动处理小的脚本来缩短one-liners。Perl还有许多其他的有用的选项,perlrun来学习细节。 3.1 -e选项 perl解释器把-e选项当做一段代码,并且执行它。命令行中的每一个-e选项当做一行代码,如果把-e选项的内容粘贴到文件中,并且用perl来 执行那个文件,将会得到和-e选项相同的结果。Code Listing16通过两个-e选项把Code Listing1重写一遍。 -----------------Code Listing16:Multiple -e Switches---------------- prompt$ perl -e ’print "Hello ";’ -e ’print "worldn";’ Hello world --------------------------------------------------------------------- 每一个代码单元[原文为code bit](外部单引号之间),在shell中被匹配成单独的标记(token),所以shell可以看见四个标记(token)在 Code Listing17中 -----------------Code Listing17:Multiple -e swithes,as tokens------ -e print "Hello "; -e print "worldn"; --------------------------------------------------------------------- 3.2 -n选项 -n选项在你的程序中封装一个while循环,在Code Listing18中,loop循环通过钻石操作符读取输入,把$_设置为读取的内容, 然后用-e选项执行代码单元。 -----------------Code Listing18:Using -n--------------------------- while (<>) { <-e argument> <-e argument> } --------------------------------------------------------------------- 在Code Listing中,重写了cat命令 -----------------Code Listing19:Reimplenmenting cat----------------- prompt$ perl -ne ’print $_’ afile --------------------------------------------------------------------- 3.3 -p选项 -p选项做同样的事,并且每次递归后输出$_的值 -----------------Code Listing20:Using -p---------------------------- while (<>) { <-e argument> <-e argument> print; } --------------------------------------------------------------------- 在Code Listing20中,循环从输入中读取数据,把读取内容赋值给$_,执行-e选项,输出$_内容,可以通过这个来修改 一个输出中的内容 例如,可以删除“ls -l”输出文件列表中关于权限的那一列。在Code Listing21中,删除了第一个非空字段以及该字段以后的空格。 -----------------Code Listing21:Remove The First Column------------- prompt$ ls -l | perl -pe ’s/S+ //’ --------------------------------------------------------------------- 3.4使用模块 通过-M开关,可以再命令行中使用模块。-M<Module>开关等同于在“虚拟脚本”中使用了“use Module”。在Code Listing22中, 使用了IO::Handle模块启动标准输出模块的自动更新。 -----------------Code Listing22:Using Module------------------------ prompt$ cat afile | perl -MIO::Handle -e ’STDOUT->autoflush(1); while (<>) { print }’ --------------------------------------------------------------------- 通常,在我的脚本中,我使用strict和warnings。而且这个也可以在one-liner中实现,在Code Listing23中, 我使用了strict,并且通过-w来启动警告开关。 -----------------Code Listing23:Using Strict------------------------ prompt$ cat afile | perl -w -Mstrict -e ’my $var = 17; print $var’ --------------------------------------------------------------------- 如果我没定义$var,strict模块如同在Code List24中那样捕获它,处理它。 -----------------Code Listing24:Undeclared Variables---------------- prompt$ cat afile | perl -w -Mstrict -e ’$var = 17; print $var’ Global symbol "$var" requires explicit package name at -e line 1. Execution of -e aborted due to compilation errors. --------------------------------------------------------------------- 在Code List25中,Perl警告我使用没有初始化的变量。 -----------------Code Listing25:Uninitialized Variables------------- cat afile | perl -w -Mstrict -e ’my $var; print $var’ Use of uninitialized value at -e line 1. --------------------------------------------------------------------- 4与shell混合使用 单双引号,如同美刀符号,都是shell的词法,如果在字符串中需要使用他们,那么必须让程序识别它们。 每个shell都有它特别的符号,不同的平台的处理方式可能不同。Code Listing26展示了处理特殊的shell元字符 的例子。 -----------------Code Listing26:Escaping Shell Metacharactors------- prompt$ echo "the variable $USER is """$USER""" " the variable $USER is "jbay" --------------------------------------------------------------------- 有几种方法可以避免shell的引用问题。在Code Listing27中,程序输出错误的SQL语句, 因为a3没有被引号括起来。单引号消失了,因为我用单引号来引用我得代码单元,但是我需要 在a3两侧加上引号,来使SQL知道a3是字符串而不是列的名字。 -----------------Code Listing27:Misquoted SQL----------------------- prompt$ perl -e ’print "select * from foo where bar=’a3’n"’ select * from foo where bar = a3 --------------------------------------------------------------------- 在Code Listing28中,我使用perl的chr()函数,通过使用它的ascii值来添加任意字符(包括单引号)。 可以把chr(39)和其他的SQL语句组合。 -----------------Code Listing28:Using Chr() To Get Literal Values--- prompt$ perl -e ’print "select * from foo where bar=" . chr(39) . "a3" . chr(39) . "n"’ select * from foo where bar=’a3’ --------------------------------------------------------------------- 在Code Listing29中,使用了通用引号操作符,q和qq来替代单双引号。我可以在perl的其他的串中使用单双引号 因为他们不再是边界定义符号。 -----------------Code Listing29:Generalized Quotes------------------ prompt$ perl -e ’print qq#select * from foo where bar="a3"n#’ select * from foo where bar="a3" --------------------------------------------------------------------- 在Code Listing30中,使用了反斜杠“”,但是语法并不是很诡异。在大多数的shell中,我使用第一个技巧来封装 优先的字符串,然后在加上“”,最后使用第三个技巧。最后在执行之前组合它们。 -----------------Code Listing30:Escaping Quote Characters----------- prompt$ perl -e ’print "select count(*) from foo where bar =’’’a3’’’n"’ select * from foo where bar =’a3’ --------------------------------------------------------------------- 5开始和结束的技巧 通过BEGIN和END关键字我可以再我得-e程序开始之前或结束之后执行代码。Code Listing31使用END在while循环结束后 输出文件总和。 -----------------Code Listing31:End Block--------------------------- ls -lAF | perl -ne ’next if /^d/; $sum += (split)[4]; END{ print "$sumn" }’ --------------------------------------------------------------------- 在Code Listing32中,程序在执行之前先执行BEGIN代码段。如果使用BEGIN块,可以在循环执行前把 $sum变量初始化为1024。 -----------------Code Listing32:Begin Block------------------------- ls -lAF | perl -ne ’BEGIN{$sum=1024} next if /^d/; $sum += (split)[4]; END{ print "$sumn" }’ --------------------------------------------------------------------- 6 参考资料: 第六章,“Social Engineering,Cooperating with Command Interpreters”,Programming Perl - Larry Wall,Tom Christiansen,& Jon Orwant. perl标准版手册以及perldoc.com在线文档http://www.perldoc.com,或者命令行perldoc pagename。 □ perlrun - perl interpreter options □ perlfaq3 “Why don’t Perl one-liners work on my DOS/Mac/VMS system?” unix在线文档http://www.bsdi.com/bsdiman/,或者命令行“man pagename”. □ find □ wc □ xargs

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读