15

单线应该:

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

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

4

24 回答 24

14

请参阅我的幻灯片以获取“Perl 命令行选项的现场指南”。

于 2008-09-21T20:02:46.677 回答
12

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

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

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

tail -f access.log | perl -ne's/([\d.]+)/localtime $1/e,print if /stackoverflow\.com/'
于 2008-09-22T00:13:44.500 回答
11

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

解决方案:重命名所有 *.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'
}
于 2008-09-21T19:43:38.923 回答
11

你可能不认为这是 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 $1}'|xargs perl -e 'print join "|" => @ARGV') aggtests/ t -l

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

于 2008-09-22T07:59:22.743 回答
9

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

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

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

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

于 2008-10-03T04:31:21.737 回答
8

来自一个地方收集的答案的所有单行:

  • 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/; rename <*.srt>, $_ }'

  • 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", 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 '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->path).qq(\n)'

有关他们的描述,请参阅相应的答案。

于 2009-02-03T18:26:48.130 回答
6

我用得最多的 Perl one-liner 是 Perl 计算器

perl -ple '$_=eval'
于 2008-10-01T22:33:34.990 回答
4

$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",
        sub{reverse @_[0..2]}->(localtime $F[0]), @F[2,4]'

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

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

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

于 2008-09-22T07:41:54.127 回答
4

@胡椒博士

删除重复的文字$PATH

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

从环境变量打印独特的干净路径%PATH%(它不接触等,如果需要../,替换File::Spec->rel2absCwd::realpath)它不是更便携的单行:

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

$, = "\n"; 
print grep { !$count{$_}++ } 
      map  { File::Spec->rel2abs($_) } 
      File::Spec->path;
于 2008-10-02T23:04:41.817 回答
3

针对Ovid 的 Vim/ack 组合

我也经常搜索一些东西,然后想在 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”放在它前面。然后整个事情被执行。

于 2008-09-22T12:23:22.203 回答
3

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

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

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

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

然后将一个纪元号通过管道传递给别名。

echo 1219174516 | e2d

Unix/Linux 上的许多程序和实用程序使用 epoch 值来表示时间,所以这对我来说是无价的。

于 2008-09-22T22:18:26.173 回答
3

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

set path=(`echo $path | perl -e 'foreach(split(/ /,<>)){print $_," " unless $s{$_}++;}'`)
于 2008-10-01T20:08:03.827 回答
3

删除 MS-DOS 行尾。

perl -p -i -e 's/\r\n$/\n/' htdocs/*.asp
于 2009-02-03T18:55:28.667 回答
3

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

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

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

我在 BAT 脚本中使用它来自动对家族中四个站点的声誉进行抽样:Stack Overflow、Server Fault、Super User 和 Meta Stack Overflow。

于 2009-09-17T18:52:40.043 回答
3

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

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

Unix(版本 1):

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

视窗(版本 2):

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

Unix/Windows(使用来自@jf-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
于 2011-01-27T15:46:49.727 回答
2

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

perl -00 -ne 'print sort split /^/'
于 2008-09-23T12:38:36.853 回答
2

在我的 ~/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 日志 | 这个脚本。

于 2009-02-04T11:38:12.900 回答
2

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

perl -e '%h=map{/.\s/;7x(ord$&&10)+$`,$_}`du -h`;print@h{sort%h}'
于 2009-09-17T18:56:27.290 回答
2

网络管理员倾向于将“子网地址”错误配置为“主机地址”,尤其是在使用 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 上测试和使用的,请建议是否应该以任何方式对其进行修改以正确使用。

于 2011-05-15T08:46:35.193 回答
1

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

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

于 2008-09-23T19:49:29.127 回答
1

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

text description {tag_label}

重要的{tag_label}是不要重复。所以有这个很好的简单脚本:

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

我知道我可以在 shell 或 perl 中做很多事情,但这是我想到的第一件事。

于 2009-09-17T23:59:21.540 回答
1

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

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} else{print @keys[$_].$F[$_] foreach(0..$#F)} " 

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

于 2011-06-25T08:16:30.103 回答
0

这是我在处理集合压缩日志文件时发现的一个方便的方法:

   open STATFILE, "zcat $logFile|" or die "Can't open zcat of $logFile" ;
于 2008-09-22T13:31:48.607 回答
-5

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

srt=(*.srt); for foo in *.avi; mv $srt[1] ${foo:r}.srt && srt=($srt[2,-1])
于 2008-09-21T22:19:40.967 回答