Perl/Unix单线Cage Match,第1部分


shell(如Bash)提供了内置命令和脚本功能,可以轻松解决和自动化各种任务。grep、sed、Awk、sort、find或parallel等外部命令可以组合使用。有时,您可以将Perl用作特定用例的单个替代或补充。

Perl是满足文本处理需求的最健壮的可移植选项。Perl有一个功能丰富的正则表达式引擎、内置函数、广泛的生态系统,并且非常便携。然而,与专用工具相比,Perl的性能可能较慢,并且可能更加冗长。

单线还是脚本?

对于数字信号处理(DSP)芯片的组装级测试,我必须为多个地址范围复制相同的场景。当时我对Linux命令行的工作知识有限,不知道如何使用sed或Awk。我使用Vim和Perl来满足各种文本处理需求。

我不知道Perl的单行程序选项,所以每当我必须替换多个文件时,我都会修改脚本。有一次,我甚至将文件作为Vim缓冲区打开,并应用了一个布夫多命令,看看这是否会使我的工作流程更简单。如果我知道Perl一行程序,我就可以很容易地利用find和Bash globs来简化我的工作,例如:

$perl-i-pe的/0xABCD/0x1234;/;s/0xDEAD/0xBEEF;/’*.测试

这个-我选项将把更改写回源文件。如果需要,我可以传递一个参数来创建原始文件的备份。例如,-i.bkp公司将创建ip文本.bkp作为的备份ip.txt(ip.txt)作为输入文件传递。我还可以将备份放在另一个现有目录中。这个*扩展为原始文件名:

$mkdir备份$perl-i'备份/*'-聚乙烯's/SEARCH/REPACE/g'*.txt文件

强大的regexp功能

Perl regexp比实用程序使用的基本或扩展正则表达式功能强大得多。我经常使用的共同特征是非贪婪和所有格量词、lookaround、/e(电子)标志、子表达式调用和(*跳过)(*失败)。以下是我多年来回答的StackOverflow线程的一些例子。

跳过一些匹配项

需要这个问题将avr-asm转换为arm-gnu注释。起始文件如下所示:

ABC r1,';'ABC r1,";"; 评论;;;

我需要改变;@,但是;在单引号或双引号内不应受到影响。我可以匹配报价;在交替和使用的第一个分支中(*跳过)(*F)不替换:

$perl-pe(美元)'s/(?:\x27;\x27|“;”)(*SKIP)(*F)|;/@/'ip.txt(ip.txt)ABC r1,';'ABC r1,";"@评论@;;

我使用(*跳过)(*F)我经常希望它有一个更短的语法,(*平方英尺)例如。

用递增值替换字符串

我可以用递增值替换字符串. The/e(电子)在替换上,我可以将替换端视为Perl代码。无论该代码的计算结果是什么,都是替换代码。这可以是我增加的变量:

$回声“a a a a”|perl-聚乙烯's/*\|*/$i++/ge'a0a1a2a3a4a5a6a

反转子字符串

我还使用了/e(电子)戏法反转与模式匹配的文本:

$回声'罗马789:qwerty12543'|perl-聚乙烯's/\d+$/reverse$&/e'罗马789:qwerty34521

做一些算术运算

添加另一个/e(电子)得到/ee公司意味着有两轮Perl代码。我对替换端进行求值,以获得将作为Perl代码求值的字符串。文本文件中的算术替换,我需要找到简单的算术,比如25100+10,并将其替换为其算术结果:

身份证件=25100+10xyz公司=1+美国广播公司=123456conf字符串=LMN、J、IP,25100+1,0,3,1

我可以用一个/e(电子)通过匹配数字并在替换端执行一些Perl操作:

$perl-pe(美元)“s/(\d+)\+(\d+/$1+2/ge”ip.txt(ip.txt)身份证件=25110xyz公司=1+美国广播公司=123456conf字符串=LMN,J,IP,25101,0,3,1

但我可以匹配整个表达式,而不是单独匹配数字。比赛开始了$&,所以第一个/e(电子)将其插入到25100+10。第二轮将其作为Perl运行,这是一个补充:

$perl-pe(美元)“s/\d+\+\d+/$&/gee”ip.txt文件身份证件=25110xyz公司=1+美国广播公司=123456conf字符串=LMN,J,IP,25101,0,3,1

这也将更容易处理一组运算符:

$回声'2+3 10-3 8*8 11/5'|perl-聚乙烯's|\d+[+/*-]\d+|$&|gee'
5 7 64 2.2

处理换行符

我想取消键入此文本:

你好。天要下雨了-天。有保险箱和愉快的jou-内尼。

与sed和Awk不同,您可以选择在Perl中保留记录分隔符。这样更容易解决这个问题:

$perl-pe(美元)'s/-\n//'消息.txt你好。今天会下雨。有保险箱和愉快的旅程。

请参见删除破折号并用空格替换换行符并将Perl解决方案与sed/Awk进行比较。

多行固定字符串替换

使用Perl中的内置功能,转义regexp元字符更简单。结合将整个输入文件转换为单个字符串,我可以轻松地执行多行固定字符串替换。考虑以下示例输入:

这是一条多行带批次的样本输入特殊字符的类似。()*[]${}^ + ?\'等等。

假设您有一个包含要匹配的行的文件:

喜欢。()*[]${}^ + ?\'等等。

以及包含替换字符串的文件:

---------------------$&=$1 + $2 / \4=====================

以下是使用Perl的一种方法:

$perl-0777-内'$#ARGV==1$s=$:$#ARGV==0$r=$_:打印s/\Q$s/$r/gr'搜索.txt替换.txt ip.txt这是一条多行带批次的样本输入特殊字符的---------------------$&=$1 + $2 / \4=====================

注意,在上述溶液中搜索.txt替换.txt也由Perl命令处理。避免使用shell变量保存其内容,因为尾部换行符和ASCII NUL字符需要特别注意。

Awk和sed没有相应的选项来吞咽整个输入文件内容。Sed是图灵完备的,Awk是一种编程语言,因此,除了转义元字符所需的代码外,如果您愿意,还可以为它编写代码。

更好的regexp支持

其他一些regexp库存在与实现它们所用的任何内容相关的问题。例如,GNU版本可能有一些其他实现可能没有的错误。您使用的版本可能会产生不同的结果。然而,Perl到处都有相同的错误。

反向引用

有一个glibc中的反向引用问题我找到的为grep报告。这个bug至少出现在grep和sed的GNU实现中。据我所知,Awk的任何实现都不支持regexp定义中的反向引用。

我想得到两次出现连续重复字符的单词。此示例花费了一些时间,结果没有输出:

$grep-xiE(美元)'([a-z]*([a-z])\2[a-z]*){2}'/usr/share/dict/words

展开嵌套或使用PCRE时,它会起作用:

$grep-xiE(美元)'[a-z]*([a-z])\1[a-z4]*([a-z])[2[a-z2]*'/usr/share/dict/words(usr/share/dict/words)雅培安娜贝利...$grep-xiP(美元)'([a-z]*([a-z])\2[a-z]*){2}'/usr/share/dict/words雅培安娜贝利...

这是Perl,它是原始的regexp:

$perl-ne(美元)'打印条件/^([a-z]*([a-z])\2[a-z]*){2}$/i'/usr/share/dict/words雅培安娜贝利...

单词边界

为什么这个sed命令不替换第三个到最后一个“and”?当涉及单词边界和组重复时,显示了另一个有趣的错误。使用glibc中的regexp代码可以看到此错误(就像在Linux上一样):

这不正确地匹配,因为“cocoa”中间没有单词边界:

$sed--版本塞德(逗号分隔符) 4.8$回声“可可”|sed-北欧'(\bco){2}/p'可可

没有量词,就没有问题,也没有匹配:

$回声“可可”|sed-北欧'/\bco\bco/p'$回声“可可”|perl-ne语言'如果/(\bco){2}/则打印'

这是GNU sed中的另一个示例。这会修改行,因为它认为“it”是在“with”之后两次作为单独的单词找到的,但第二次实际上位于“sit”的中间:

$回声“它和它排在一起,也坐在这里”|sed-电子's/with(.*\bit\b){2}/XYZ/'它也行XYZ

更改模式以去掉量词,它就会正常工作:

$echo(回声)“它和它排在一起,也坐在这里”|sed-电子's/with.*\bit\b.*\比特\b/XYZ/'它和它排成一线,也坐在这里$回声“它和它在这里排成一行,也坐在这里”|sed-电子's/with.*\bit\b.*\比特\b/XYZ/'它线XYZ#Perl不需要这样的解决方法$回声“它和它排在一起,也坐在这里”|perl-聚乙烯's/with(.*\bit\b){2}/XYZ/'它和它排成一线,也坐在这里$回声“它和它在这里排成一行,也坐在这里”|perl-聚乙烯's/with(.*\bit\b){2}/XYZ/'它线XYZ

敬请期待

我将在第2部分中介绍更多内容,在这里我将深入研究XML、JSON和CSV。

其他需要阅读的内容


[图像来自点心!在Flickr上,(CC BY-NC-ND 2.0)]

标签

桑德普·阿加瓦尔

Sundeep Agarwal沉迷于写作阅读小说(主要是幻想小说和科幻小说)。

浏览他们的文章

反馈

这篇文章有什么问题吗?通过在上打开问题或拉取请求来帮助我们github