最新的有用的Perl单线衬里(或者涉及Perl的管道)是什么?
一线客:
- 解决现实世界中的问题
- 不太广泛(应该易于理解和复制)
- 值得花时间写(不要太聪明)
我正在寻找实用的技巧和窍门(perldoc perlrun的补充示例)。
解决方案
问题:媒体播放器不会自动加载字幕,因为其名称与相应的视频文件不同。
解决方案:重命名所有* .srt(带字幕的文件)以匹配* .avi(带视频的文件)。
perl -e'while(<*.avi>) { s/avi$/srt/; rename <*.srt>, $_ }'
注意:原始视频和字幕文件名的排序顺序应该相同。
这里是上述单行代码的更详细的版本:
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' }
请参阅我的幻灯片" Perl命令行选项领域指南"。
有时我发现,只要使用普通的ZSH功能,只要用perl -e在命令行中完成足够短的操作,就可以做得更好,更轻松,更快,而又不必担心引用问题。例如。上面的示例可以这样完成:
for foo in *.avi; mv *.srt ${foo:r}.srt
更新
上面的onliner确实是错误的,对不起我们没有仔细阅读。这是正确的版本:
srt=(*.srt); for foo in *.avi; mv $srt[1] ${foo:r}.srt && srt=($srt[2,-1])
鱿鱼日志文件。他们很棒,不是吗?除非默认情况下,否则它们以"秒数"作为时间字段。这是一种从乌贼日志文件读取并将时间转换为人类可读日期的单线代码:
perl -pe's/([\d.]+)/localtime /e;' access.log
进行一些细微的调整,就可以使其仅显示带有我们感兴趣的关键字的行。以下注意stackoverflow.com的用户仅访问并打印这些行,并带有易于理解的日期。为了使它更有用,我给它提供了tail -f的输出,以便可以实时查看访问:
tail -f access.log | perl -ne's/([\d.]+)/localtime /e,print if /stackoverflow\.com/'
$ work上最大的带宽消耗之一是下载网络广告,所以我正在寻找等待中的低挂水果。我已经摆脱了Google广告的束缚,现在将Microsoft纳入了我的视野。因此,我在日志文件上拖了一条尾巴,并选择了感兴趣的行:
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", sub{reverse @_[0..2]}->(localtime $F[0]), @F[2,4]'
Perl管道的工作是通过将autoflush设置为true开始的,这样,所有作用于其上的东西都会立即打印出来。否则,它的输出将被分块,并且在输出缓冲区填满时会收到一批行。 -a开关在空格上分割每条输入行,并将结果保存在数组@F中(功能受awk将输入记录分为$ 1,$ 2,$ 3 ...变量的能力启发)。
它检查该行的第7个字段是否包含我们要查找的URI(使用\ Q可以避免转义无趣的元字符的麻烦)。如果找到匹配项,它将漂亮地打印时间,源IP和从远程站点返回的字节数。
通过获取第一个字段中的纪元时间并使用" localtime"将其细分为各个部分(小时,分钟,秒,日,月,年)来获得时间。它需要前三个元素的一部分返回,第二,分钟和小时,然后颠倒顺序以获取小时,分钟和秒。它作为三元素数组以及原始@F数组的第三个(IP地址)和第五个(大小)的切片返回。这五个参数传递给sprintf,后者对结果进行格式化。
我们可能不会认为这是Perl,但是我虔诚地使用ack(这是用Perl编写的智能grep替代品),这使我可以编辑所有访问我们API特定部分的Perl测试:
vim $(ack --perl -l 'api/v1/episode' t)
附带说明一下,如果使用vim,则可以在编辑器的缓冲区中运行所有测试。
对于具有更明显(如果简单)的Perl的东西,我需要知道t / lib / TestPM目录中有多少测试程序用尽了测试夹具(为了清楚起见,我已经削减了命令)。
ack $(ls t/lib/TestPM/|awk -F'.' '{print }'|xargs perl -e 'print join "|" => @ARGV') aggtests/ t -l
请注意," join"如何将结果转换为正则表达式以馈送给ack。
针对Ovids vim / ack组合:
我也经常在找东西,然后想在Vim中打开匹配的文件,所以前段时间我做了一个捷径(我认为只能在ZSH中使用):
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"。我查看结果,如果喜欢,可以再次按向上箭头以获取确认行,然后按CTRL + P。然后发生的情况是,仅当命令以" ack"开头时,ZSH才追加并使用" -l"列出文件名。然后在命令前加上" $(...)",并在命令前加上" vim"。然后整个事情被执行。
这是我在处理集合压缩日志文件时觉得很方便的一个:
open STATFILE, "zcat $logFile|" or die "Can't open zcat of $logFile" ;
我经常使用它来快速将纪元时间转换为有用的日期戳。
perl -l -e 'print scalar(localtime($ARGV[0]))'
在shell中创建一个别名:
alias e2d="perl -le \"print scalar(localtime($ARGV[0]));\""
然后,将纪元号传递给别名。
echo 1219174516 | e2d
Unix / Linux上的许多程序和实用程序都使用纪元值来表示时间,因此这对我来说非常宝贵。
过滤由空格分隔的节流(名称/值对列表),
分别对每个节进行排序:
perl -00 -ne 'print sort split /^/'
将所有标签扩展到空格:perl -pe'1while + s / \ t /"" x(8-pos()%8)/ e'
当然,这可以通过Vim中的:set et,:ret来完成。
删除路径变量中的重复项:
set path=(`echo $path | perl -e 'foreach(split(/ /,<>)){print $_," " unless $s{$_}++;}'`)
我使用最多的Perl线性是Perl计算器
perl -ple '$_=eval'
@胡椒博士
删除$ PATH中的文字重复项:
$ export PATH=$(perl -F: -ane'print join q/:/, grep { !$c{$_}++ } @F'<<<$PATH)
从%PATH%
环境变量中打印唯一的干净路径(它不会碰到../等,如果需要的话,用Cwd :: realpath
替换File :: Spec-> rel2abs
)不是单线的,更便于携带:
#!/usr/bin/perl -w use File::Spec; $, = "\n"; print grep { !$count{$_}++ } map { File::Spec->rel2abs($_) } File::Spec->path;
使用find ... -exec rm {} \;
删除目录树中某处文件的常见习惯并不是特别有效,因为它对找到的每个文件执行一次rm命令。我的习惯之一是从计算机不那么快的时代诞生的(dagnabbit!),用一个对perl的调用代替了对rm的许多调用:
find . -name '*.whatever' | perl -lne unlink
命令行的" perl"部分读取由" find"发出的文件列表*,每行一个,修剪掉换行符,并使用perl的内置" unlink()"函数删除该文件,该函数使用$如果未提供显式参数,则以_`作为其参数。 (由于有-n标志,$ _被设置为输入的每一行。)(*最近,大多数" find"命令默认情况下都执行" -print",因此我可以省去那一部分。)
我喜欢这个习惯用法,不仅因为它的效率(如今可能不那么重要),还因为它比输入传统的-exec rm {} \;
序列具有更少的弦/笨拙的键。它还避免了引号引起的问题,这些文件名带有空格,引号等,其中有很多。 (一个更健壮的版本可能使用find
的-print0
选项,然后要求perl
读取以空分隔的记录而不是行,但是我通常非常有信心我的文件名不包含嵌入的换行符。 )
来自一处收集的答案的所有单行代码:
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(<。avi>){s / avi $ / srt /;重命名<。srt>,$ _}'`
找到。名称'* .whatever'| perl -lne解除连结
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", sub {reverse @_ [0..2]}->(localtime $ F [0]),@F [2,4]'
export PATH = $(perl -F:-ane'print join q /:/,grep {!$ c {$ _} ++} @F'<<< $ PATH)
alias e2d =" perl -le \" print scalar(localtime($ ARGV [0])); \""
- perl -ple'$ _ = eval'`
- perl -00 -ne'打印排序拆分/ ^ /'`
- 'perl -pe'1while + s / \ t /"" x(8-pos()%8)/ e'`
tail -f log | perl -ne'$ s = time()除非$ s; $ n = time(); $ d = $ n- $ s; if($ d> = 2){print qq($。last $ d secs,rate),$。/ $ d,qq(\ n); $。 = 0; $ s = $ n; }'
- perl -MFile :: Spec -e'打印连接(qq(\ n),File :: Spec-> path).qq(\ n)'
有关说明,请参见相应的答案。
删除MS-DOS线尾。
perl -p -i -e 's/\r\n$/\n/' htdocs/*.asp
在我的〜/ 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; }'
我们可以将其用于日志文件的尾部,它将打印输出的行数。
是否想知道Web服务器每秒获得多少点击?尾-f日志| this_script。
无需打开网页即可提取Stack Overflow信誉:
perl -nle "print ' Stack Overflow ' . . ' (no change)' if /\s{20,99}([0-9,]{3,6})<\/div>/;" "SO.html" >> SOscores.txt
假设用户页面已经下载到文件SO.html。我为此目的使用wget。此处的注释适用于Windows命令行;对于Linux或者Mac OS X,它会稍有不同。输出将添加到文本文件中。
我在BAT脚本中使用它来自动进行家庭四个站点上的声誉采样:
堆栈溢出,服务器故障,超级用户和元堆栈溢出。
从du
获取人类可读的输出,按大小排序:
perl -e '%h=map{/.\s/;7x(ord$&&10)+$`,$_}`du -h`;print@h{sort%h}'
我有一个标签列表,可用来标识文本的各个部分。主列表的格式为:
text description {tag_label}
请勿重复{tag_label}`,这一点很重要。因此,有一个很好的简单脚本:
perl -ne '($c) = $_ =~ /({.*?})/; print $c,"\n" ' | sort | uniq -c | sort -d
我知道我可以在shell或者perl中完成全部工作,但这是我想到的第一件事。