您最新的有用 Perl 单线(或涉及 Perl 的管道)是啥? [关闭]

Posted

技术标签:

【中文标题】您最新的有用 Perl 单线(或涉及 Perl 的管道)是啥? [关闭]【英文标题】:What is your latest useful Perl one-liner (or a pipe involving Perl)? [closed]您最新的有用 Perl 单线(或涉及 Perl 的管道)是什么? [关闭] 【发布时间】:2010-09-11 19:55:35 【问题描述】:

单行应该:

解决实际问题 不要过于神秘(应该易于理解和重现) 值得花时间写它(不应该太聪明)

我正在寻找实用的提示和技巧(perldoc perlrun 的补充示例)。

【问题讨论】:

"last" 的意思是“final”,因为我再也不会写另一个了。那不会发生的。只要提示接受,我将继续编写 Perl 单行代码。也许你的意思是“最新的”。 谢谢。我已经更正了标题。我最后一顿饭的时间还没到:) 【参考方案1】:

请看我的幻灯片"A Field Guide To The Perl Command Line Options."

【讨论】:

`-e 示例幻灯片:在 Windows 上,我更喜欢 q() 和 qq() 而不是引号。它允许我通过仅替换两个外部引号来使用相同的 Linux 单行代码。 Windows:perl -E"say q(Hello, World)"。 Linux:perl -E'say q(Hello, World)' 死链接... 镜像链接:web.archive.org/web/20120916013412/http://petdance.com/perl/…【参考方案2】:

鱿鱼日志文件。他们很棒,不是吗?除了默认情况下,它们将秒数作为时间字段。这是一个从 squid 日志文件中读取并将时间转换为人类可读日期的单行程序:

perl -pe's/([\d.]+)/localtime $1/e;' access.log

只需稍加调整,您就可以使其仅显示带有您感兴趣的关键字的行。***.com 的以下监视仅访问和打印这些行,并带有人类可读的日期。为了让它更有用,我给它输出tail -f,这样我就可以实时看到访问:

tail -f access.log | perl -ne's/([\d.]+)/localtime $1/e,print if /***\.com/'

【讨论】:

【参考方案3】:

问题:媒体播放器不会自动加载字幕,因为它们的名称与对应的视频文件不同。

解决方案:重命名所有 *.srt(带字幕的文件)以匹配 *.avi(带视频的文件)。

perl -e'while(<*.avi>)  s/avi$/srt/; rename <*.srt>, $_ '

CAVEAT:原始视频和字幕文件名的排序顺序应相同。

这里是上述单行代码的更详细版本:

my @avi = glob('*.avi');
my @srt = glob('*.srt');

for my $i (0..$#avi)

  my $video_filename = $avi[$i];
  $video_filename =~ s/avi$/srt/;   # 'movie1.avi' -> 'movie1.srt'

  my $subtitle_filename = $srt[$i]; # 'film1.srt'
  rename($subtitle_filename, $video_filename); # 'film1.srt' -> 'movie1.srt'

【讨论】:

【参考方案4】:

你可能不认为这是 Perl,但我虔诚地使用 ack(这是一个用 Perl 编写的智能 grep 替代品),这让我可以编辑,例如,我所有的 Perl 测试,这些测试访问我们的特定部分接口:

vim $(ack --perl -l 'api/v1/episode' t)

附带说明,如果你使用 vim,你可以run all of the tests in your editor's buffers。

对于更明显(如果简单的话)Perl 的东西,我需要知道有多少测试程序用尽了 t/lib/TestPM 目录中的测试装置(为了清楚起见,我已经删减了命令)。

ack $(ls t/lib/TestPM/|awk -F'.' 'print $1'|xargs perl -e 'print join "|" => @ARGV') aggtests/ t -l

请注意“加入”如何将结果转换为正则表达式以供 ack 使用。

【讨论】:

【参考方案5】:

使用find ... -exec rm \; 删除目录树中某处的一组文件的常见习惯用法并不是特别有效,因为它为找到的每个文件执行一次rm 命令。我的一个习惯是在计算机还没有那么快(dagnabbit!)的时候出生的,就是用一个 perl 调用代替对 rm 的多次调用:

find . -name '*.whatever' | perl -lne unlink

命令行的perl 部分读取find 发出的文件列表*,每行一个,修剪换行符,并使用perl 的内置unlink() 函数删除文件,该函数采用@如果没有提供显式参数,则 987654329@ 作为其参数。 (由于-n 标志,$_ 被设置为每一行输入。)(*现在,大多数find 命令默认使用-print,所以我可以省略这部分。)

我喜欢这个习语,不仅因为它的效率(现在可能不那么重要了),还因为它比输入传统的-exec rm \; 序列具有更少的和弦/尴尬键。它还避免了由带有空格、引号等的文件名引起的引用问题,其中我有很多。 (更强大的版本可能使用find-print0 选项,然后要求perl 读取以空值分隔的记录而不是行,但我通常非常确信我的文件名不包含嵌入的换行符。)

【讨论】:

在 Perl 还没有出现在 Larry 眼中之前,我一直在使用 xargs 来解决这个问题 :-)。 公平,因为它是 Perl 相关的主题;但另一个更强大的 POSIX 版本可以使用 find ... -print0 | xargs -0 -- rm 或使用 GNU findutils:find ... --exec rm + ⁽ʳᵉᶠ⁾【参考方案6】:

所有答案都集中在一个地方:

perl -pe's/([\d.]+)/localtime $1/e;' access.log

ack $(ls t/lib/TestPM/|awk -F'.' 'print $1'|xargs perl -e 'print join "|" => @ARGV') aggtests/ t -l

perl -e'while(&lt;*.avi&gt;) s/avi$/srt/; rename &lt;*.srt&gt;, $_ '

find . -name '*.whatever' | perl -lne unlink

tail -F /var/log/squid/access.log | perl -ane 'BEGIN$|++ $F[6] =~ m\Qrad.live.com/ADSAdClient31.dll && printf "%02d:%02d:%02d %15s %9d\n", subreverse @_[0..2]->(localtime $F[0]), @F[2,4]'

export PATH=$(perl -F: -ane'print join q/:/, grep !$c$_++ @F'&lt;&lt;&lt;$PATH)

alias e2d="perl -le \"print scalar(localtime($ARGV[0]));\""

perl -ple '$_=eval'

perl -00 -ne 'print sort split /^/'

perl -pe'1while+s/\t/" "x(8-pos()%8)/e'

tail -f log | perl -ne '$s=time() unless $s; $n=time(); $d=$n-$s; if ($d>=2) print qq ($. lines in last $d secs, rate ),$./$d,qq(\n); $. =0; $s=$n; '

perl -MFile::Spec -e 'print join(qq(\n),File::Spec-&gt;path).qq(\n)'

查看相应答案的描述。

【讨论】:

【参考方案7】:

我用得最多的 Perl 单行是 Perl 计算器

perl -ple '$_=eval'

【讨论】:

如果您运行的是 Perl 5.10,您可以运行 perl -plE '$_=eval' 来启用 5.10 的功能。【参考方案8】:

$work 最大的带宽消耗之一是下载网络广告,所以我正在寻找等待采摘的低垂果实。我已经摆脱了谷歌广告,现在我的视线中有微软。所以我在日志文件上运行了一个tail,并挑选出感兴趣的行:

tail -F /var/log/squid/access.log | \
perl -ane 'BEGIN$|++ $F[6] =~ m\Qrad.live.com/ADSAdClient31.dll
    && printf "%02d:%02d:%02d %15s %9d\n",
        subreverse @_[0..2]->(localtime $F[0]), @F[2,4]'

Perl 管道所做的是首先将 autoflush 设置为 true,以便立即打印出任何被执行的操作。否则,它会将输出分块,并且当输出缓冲区填满时会收到一批行。 -a 开关在空白处拆分每个输入行,并将结果保存在数组 @F 中(该功能的灵感来自 awk 将输入记录拆分为其 $1、$2、$3... 变量的能力)。

它检查该行中的第 7 个字段是否包含我们寻找的 URI(使用 \Q 来避免我们逃避无趣的元字符的痛苦)。如果找到匹配项,它会漂亮地打印时间、源 IP 和从远程站点返回的字节数。

时间是通过在第一个字段中获取纪元时间并使用“本地时间”将其分解为其组成部分(小时、分钟、秒、日、月、年)来获得的。它取前三个元素的切片返回,秒、分和小时,并颠倒顺序得到小时、分钟和秒。这作为一个三元素数组返回,以及来自原始 @F 数组的第三个(IP 地址)和第五个(大小)的切片。这五个参数被传递给 sprintf 来格式化结果。

【讨论】:

【参考方案9】:

@dr_pepper

删除$PATH中的文字重复:

$ export PATH=$(perl -F: -ane'print join q/:/, grep  !$c$_++  @F'<<<$PATH)

%PATH% 环境变量打印唯一的干净路径(它不会触及../ 等,如果需要,将File::Spec-&gt;rel2abs 替换为Cwd::realpath)它不是更便携的单行:

#!/usr/bin/perl -w
use File::Spec; 

$, = "\n"; 
print grep  !$count$_++  
      map   File::Spec->rel2abs($_)  
      File::Spec->path;

【讨论】:

感谢您向我展示这一点,我正在寻找更短的单线来执行此操作。在我的环境中,使用小写 $path 时,空格是分隔符。使用大写 $PATH 更好吗? 在我的 shell (bash) 中,$path 和 $PATH 是不同的变量(名称区分大小写:$ a=2; A=3; echo $(($a * $A)) 这个打印“6”。 可以使用trsortuniqcut 和管道程序的组合来删除重复项。 但是,使用 tr、sort 等会改变路径顺序,可能会导致不良副作用。 在ZSH中变量path绑定变量PATH,所以PATH总是path的元素,用冒号连接,path总是包含PATH 的块按列拆分。要使它们唯一,只需将 -U 修饰符应用于变量之一: typeset -U PATH【参考方案10】:

我经常使用它来快速将纪元时间转换为有用的日期戳。

perl -l -e 'print scalar(localtime($ARGV[0]))'

在你的 shell 中创建一个别名:

alias e2d="perl -le \"print scalar(localtime($ARGV[0]));\""

然后将一个纪元编号传递给别名。

echo 1219174516 | e2d

Unix/Linux 上的许多程序和实用程序使用 epoch 值来表示时间,因此这对我来说非常宝贵。

【讨论】:

要从纪元秒中获取可读的日期戳,您还可以使用带有@符号的 GNU 日期:date --date=@1219174516【参考方案11】:

删除路径变量中的重复项:

set path=(`echo $path | perl -e 'foreach(split(/ /,<>))print $_," " unless $s$_++;'`)

【讨论】:

$path 中路径之间的分隔符是什么?看我的回答。【参考方案12】:

删除 MS-DOS 行尾。

perl -p -i -e 's/\r\n$/\n/' htdocs/*.asp

【讨论】:

1. -i 需要后缀,例如 -i.bak。 2. 无法在 Windows 上运行。 我想知道如何在 Windows 中做 Perl 派。感谢您的提示。【参考方案13】:

无需打开网页即可提取 Stack Overflow 信誉:

perl -nle "print '  Stack Overflow        ' . $1 . '  (no change)' if /\s20,99([0-9,]3,6)<\/div>/;" "SO.html"  >> SOscores.txt

这假设用户页面已经下载到文件 SO.html。我为此目的使用 wget。这里的符号是针对 Windows 命令行的;对于 Linux 或 Mac OS X 会略有不同。输出附加到文本文件中。

我在 BAT 脚本中使用它来自动对家族中四个站点的声誉进行抽样: 堆栈溢出、服务器故障、超级用户和元堆栈溢出。

【讨论】:

【参考方案14】:

回复Ovid's Vim/ack combination:

我也经常搜索一些东西,然后想在 Vim 中打开匹配的文件,所以我前段时间给自己做了一个小快捷方式(我想只在 Z shell 中工作):

function vimify-eval; 
    if [[ ! -z "$BUFFER" ]]; then
        if [[ $BUFFER = 'ack'* ]]; then
            BUFFER="$BUFFER -l"
        fi
        BUFFER="vim  \$($BUFFER)"
        zle accept-line
    fi


zle -N vim-eval-widget vimify-eval

bindkey '^P' vim-eval-widget

它的工作原理是这样的:我使用 ack 搜索一些东西,比如ack some-pattern。我查看结果,如果我喜欢它,我按向上箭头再次获取 ack-line,然后按 Ctrl + P。然后发生的情况是,仅当命令以“ack”开头时,Z shell 才会附加和“-l”以列出文件名。然后它把“$(...)”放在命令周围,把“vim”放在它前面。然后整个事情都被执行了。

【讨论】:

【参考方案15】:

在编写 shell 脚本时,我经常需要查看 PATH 的可读版本。以下单行将每个路径条目打印在自己的行上。

随着时间的推移,这种单线已经经历了几个阶段:

Unix(版本 1):

perl -e 'print join("\n",split(":",$ENV"PATH"))."\n"'

Windows(第 2 版):

perl -e "print join(qq(\n),split(';',$ENV'PATH')).qq(\n)"

Unix/Windows(使用来自@j-f-sebastian 的 q/qq 提示)(版本 3):

perl -MFile::Spec -e 'print join(qq(\n), File::Spec->path).qq(\n)' # Unix
perl -MFile::Spec -e "print join(qq(\n), File::Spec->path).qq(\n)" # Windows

【讨论】:

perl -MFile::Spec -E '$,=qq(\n); say File::Spec-&gt;path' perl -MFile::Spec::Functions -E '$,=qq(\n); say path' @J.F. Sebastian:当使用 -E 运行时,我在 Windows 和 UNIX 上都得到Unrecognized switch: -E (-h will show valid options).。我在两个平台上都运行 perl v5.8.8。 -E 启用可选功能,例如 say()5.10(自 2007 年起)。 @J.F. Sebastian:谢谢,这是一个有用的花絮!【参考方案16】:

在我的 ~/bin 中占有一席之地的最新单行代码之一:

perl -ne '$s=time() unless $s; $n=time(); $d=$n-$s; if ($d>=2)  print "$. lines in last $d secs, rate ",$./$d,"\n"; $. =0; $s=$n; '

您可以在日志文件的尾部使用它,它会打印输出行的速率。

想知道您的网络服务器每秒获得多少点击?尾 -f 日志 | this_script。

【讨论】:

它是一个迷你管道查看器 (pv) ivarch.com/programs/pv.shtml>。但是你的单行代码可以在 Windows 上运行。【参考方案17】:

du 获取人类可读的输出,按大小排序:

perl -e '%h=map/.\s/;7x(ord$&&10)+$`,$_`du -h`;print@hsort%h'

【讨论】:

【参考方案18】:

过滤以空格分隔的节流(名称/值对列表), 分别对每个节进行排序:

perl -00 -ne 'print sort split /^/'

【讨论】:

sort() 将在段落顶部放置空行。我猜你实际上是这个意思: perl -00 -ne'($n, @a) = sort split /^/; print @a, $n' 如果最后一段之后没有换行符,则两个单行都会失败。【参考方案19】:

网络管理员倾向于将“子网地址”错误配置为“主机地址”,尤其是在使用 Cisco ASDM 自动建议时。这种简单的单行扫描配置文件以查找任何此类配置错误。

错误用法:permit host 10.1.1.0

正确用法:permit 10.1.1.0 255.255.255.0

perl -ne "print if /host ([\w\-\.]+)3\.0 /" *.conf

这是在 Windows 上测试和使用的,请建议是否应该以任何方式对其进行修改以正确使用。

【讨论】:

【参考方案20】:

将所有制表符扩展到空格:perl -pe'1while+s/\t/" "x(8-pos()%8)/e'

当然,这可以通过 Vim 中的 :set et, :ret 来完成。

【讨论】:

perl -pe'1while+s/\t/" "x(8-(pos)%8)/e' 需要括号。【参考方案21】:

我有一个标签列表,我用它来识别部分文本。主列表的格式为:

text description tag_label

tag_label 不能重复,这一点很重要。所以有这个不错的简单脚本:

perl -ne '($c) = $_ =~ /(.*?)/; print $c,"\n" ' $1 | sort  | uniq -c | sort -d

我知道我可以在 shell 或 perl 中完成所有工作,但这是我首先想到的。

【讨论】:

perl -ne'$f$1++ while /(.*?)/g; END print "$f$_ $_\n" for (sort $f$a &lt;=&gt; $f$b keys %f) ' $1。你是对的,对于这样的任务,首先要考虑的事情就足够了。顺便说一句,你确定每行只能有一个标签吗?【参考方案22】:

我经常不得不将表格数据转换为配置文件。例如,网络布线供应商以 Excel 格式提供修补记录,我们必须使用该信息来创建配置文件。即,

Interface, Connect to, Vlan
Gi1/0/1, Desktop, 1286
Gi1/0/2, IP Phone, 1317

应该变成:

interface Gi1/0/1
 description Desktop
 switchport access vlan 1286

等等。相同的任务在各种管理任务中以多种形式重新出现,其中需要在表格数据前面加上其字段名称并转换为平面结构。我已经看到一些 DBA 浪费了很多时间从 excel 表中准备他们的 SQL 语句。可以使用这个简单的单线来实现。只需使用您最喜欢的电子表格工具将表格数据保存为 CSV 格式并运行此单行。标题行中的字段名称会添加到各个单元格值的前面,因此您可能需要对其进行编辑以符合您的要求。

perl -F, -lane "if ($.==1) @keys = @F elseprint @keys[$_].$F[$_] foreach(0..$#F) " 

需要注意的是,任何字段名称或值都不应包含任何逗号。也许这可以进一步阐述以在一行中捕获此类异常,如果可能,请改进这一点。

【讨论】:

【参考方案23】:

在处理集合压缩日志文件时,我觉得很方便:

   open STATFILE, "zcat $logFile|" or die "Can't open zcat of $logFile" ;

【讨论】:

单行是指一行中的整个程序,而不是程序中有用的一行。 我自己实际上会把它分成两行或更多行。【参考方案24】:

有时我发现我想用 Perl 做的任何事情只要用“perl -e”在命令行上完成就可以用普通的 Z shell 功能做得更好、更容易、更快捷,而没有麻烦的引用。例如。上面的例子可以这样完成:

srt=(*.srt); for foo in *.avi; mv $srt[1] $foo:r.srt && srt=($srt[2,-1])

【讨论】:

glob-in-scalar-context 真的很容易出错;应尽可能避免。 新版本不会因为 mv 故障而失去同步吗? 嗯,这个东西的整个想法有点不稳定,因为它假设每个 .avi 都有一个 .srt,并且当按字母顺序排序时,每个 avi/srt 对都在相同的位置在列表中。但是,您可以将 && 替换为 ;并在它周围放上大括号。 ;)

以上是关于您最新的有用 Perl 单线(或涉及 Perl 的管道)是啥? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

Perl 的 system() 如何打印它正在运行的命令?

是否可以将 perl6 嵌入到 C(或 C++)程序中?

您可以强制标量或数组 ref 成为 Perl 中的数组吗?

如何使用 PHP 中的 Perl 库?

'perl' 不是内部或外部命令,也不是可运行的程序

如何从 Perl 创建或读取 OpenOffice 电子表格?