我刚刚写了我写过的最扭曲的命令,我想知道如何才能使它变得更好。
我写了这个:
grep -E '00[7-9]\.|0[1-9][0-9]\.' filename.log | awk '{print $6}' | sed 's/\(.*\):.*/\1/' | sort | uniq -c | sort -rn
输入示例:
2011/06/30 07:59:43:81 20626 code_file.c (252): FunctionName: 009.63 seconds
它所做的基本上是查看一个日志文件,该文件列出了命令执行所花费的秒数,并抓取其中执行时间在 7 到 99 秒之间的任何命令。然后 awk 打印第六个单词,即函数名称后跟一个冒号。然后 sed 删除冒号和任何尾随空格,然后对其进行排序、计数,然后根据计数进行排序。
我使用的是 HP-UX,因此某些工具功能有限,但我知道 awk 可以完成我刚刚用 sed 完成的操作。有人能帮我简化命令吗?
答案1
awk '/00[7-9]\.|0[1-9][0-9]\./ { # for lines matching the regex
split($6, c, /:/) # take the part of field 6 before the colon
cs[ c[1] ]++ # and increment the counter for that string
}
END { # after all lines have been read
for (c in cs) { # step through the counters
print cs[c], c # and output the count followed by the string
# ("," adds a space automatically)
}
}' filename.log | sort -rn # standard awk doesn't support sorting, sadly
我继续对如此多的人感到惊讶,他们显然认为 either awk
norsed
不能进行模式匹配,所以他们必须添加grep
调用。
答案2
我是所以将会因这个而被否决......
#!/usr/bin/env perl
use strict;
my %counts;
while (my $line = <>) {
my @line = split(/\s+/, $line);
if ($line[6] >= 7) {
$line[5] =~ /(.+):/ and $counts{$1}++;
}
}
my @sorted = sort {$counts{$b} <=> $counts{$a}} keys %counts;
printf("%7d\t%s\n", $counts{$_}, $_) for @sorted;
答案3
您的命令有点脆弱,因为如果文件名中有空格,它将失败。除此之外,您的命令实际上还不错。这在某种程度上是一个品味问题,但我发现一串简单的管道命令比一个复杂的命令(例如某人发布的大型 awk)更容易理解。它几乎可能是以函数式风格进行编程。
但是,您可以更改 grep 以消除 awk 和 sed,但现在正则表达式变得更难理解:
grep -P -o '(?<=\): ).+?(?=: 00[7-9]|0[1-9]|1)' | sort | uniq -c | sort -nr
为了解释正则表达式,我们使用 perl 样式 re (-P param),并使用后视 (?<=) 和前视 (?=) 将匹配项精确地隔离到函数名称。请注意,后视和前视是零宽度,这意味着它们不被视为匹配项的一部分,但控制匹配项的实际内容。由于匹配项现在精确地是函数名称,我们可以使用 -o 来告诉 grep 仅打印匹配的字符串而不是整行。我认为你应该保留你所拥有的,除非你认为文件名带有空格是可能的。
答案4
当我这样做的时候:
#!/bin/sh
grep -E '00[7-9]\.|0[1-9][0-9]\.' "$@" | awk '{print $6}' |
sed 's/:$//' | sort | uniq -c | sort -rn
原始命令并不复杂,只是每个日志的重复才让它看起来如此。将它粘贴到脚本文件(或函数)中,调用它sortbytime
,这样你就有了一个简单的单词命令。