输入文件
Mar 19 06:10:16 ip-172-2-0-53 sendmail[28131]: v2JDA1k4028131: to=root, ctladdr=root (0/0), delay=00:00:15, xdelay=00:00:00, mailer=relay, pri=30580, relay=[127.0.0.1] [127.0.0.1], dsn=2.0.0, stat=Sent (v2JDAG5W028134 Message accepted for delivery)
Mar 19 14:41:26 ip-172-2-0-53 sendmail[29483]: v2JLfNFN029481: to=<[email protected]>,<[email protected]>, delay=00:00:03, xdelay=00:00:03, mailer=esmtp, pri=151738, relay=ifaded-com.mail.p...ction.outlook.com. [xx.xxx.x.x], dsn=2.0.0, stat=Sent (<[email protected]> [InternalId=31288836753166, Hostname=ERGsDGddssdD5.namprd07.prod.outlook.com] 8924 bytes in 0.309, 28.142 KB/sec Queued mail for delivery)
Mar 19 06:10:26 ip-172-2-0-53 sendmail[28131]: v2JDA1k4028131: to=root, ctladdr=root (0/0), delay=00:20:15, xdelay=00:00:00, mailer=relay, pri=30580, relay=[127.0.0.1] [127.0.0.1], dsn=2.0.0, stat=Sent (v2JDAG5W028134 Message accepted for delivery)
我尝试过以下命令
cat logh.txt | grep -E -o " delay=.[^,]*|^[^ip]+"
我想找出日期前 5 个延迟时间,如何使用 llinux 命令解决这个问题。我得到以下输出
Mar 19 06:10:16
delay=00:00:15
Mar 19 14:41:26
delay=00:00:03
Mar 19 06:10:26
delay=00:20:15
所需输出
Mar 19 06:10:26 delay=00:20:15
Mar 19 06:10:16 delay=00:00:15
Mar 19 14:41:26 delay=00:00:03
答案1
您将需要多次通行证。这是一个使用sed
、sort
、head
和cut
按您想要的顺序给出前 5 个的解决方案。
sed -e 's/^\([A-Za-z]\{3\} \{1,2\}[0-9]\{1,2\} \{1,2\}\([0-9]\{2\}:\)\{2\}[0-9]\{2\}\).* \(delay=\([0-9]\{2\}\):\([0-9]\{2\}\):\([0-9]\{2\}\)\).*/\4\5\6 \1 \3/' | sort -nr | head -n5 | cut -d\ -f2-
根据您提供的输入,这会发出:
Mar 19 06:10:26 delay=00:20:15
Mar 19 06:10:16 delay=00:00:15
Mar 19 14:41:26 delay=00:00:03
(假设其输入采用您提供的日志格式,并且仅向行提供您想要的数据。可能需要在开头添加额外的 grep。)
它在做什么
让我们来分解一下。
sed
sed
代表流编辑器。它通常用于将正则表达式应用于文本流。
sed的正则表达式
's/^\([A-Za-z]\{3\} \{1,2\}[0-9]\{1,2\} \{1,2\}\([0-9]\{2\}:\)\{2\}[0-9]\{2\}\).* \(delay=\([0-9]\{2\}\):\([0-9]\{2\}\):\([0-9]\{2\}\)\).*/\4\5\6 \1 \3/'
这是相当拗口的,但它是必要的,以避免灾难性的回溯。
我们正在使用正则表达式替换。要详细了解它在做什么,尝试正则表达式101。现在,知道它需要输入:
Mar 19 06:10:16 ip-172-2-0-53 sendmail[28131]: v2JDA1k4028131: to=root, ctladdr=root (0/0), delay=00:00:15, xdelay=00:00:00, mailer=relay, pri=30580, relay=[127.0.0.1] [127.0.0.1], dsn=2.0.0, stat=Sent (v2JDAG5W028134 Message accepted for delivery)
Mar 19 14:41:26 ip-172-2-0-53 sendmail[29483]: v2JLfNFN029481: to=<[email protected]>,<[email protected]>, delay=00:00:03, xdelay=00:00:03, mailer=esmtp, pri=151738, relay=ifaded-com.mail.p...ction.outlook.com. [xx.xxx.x.x], dsn=2.0.0, stat=Sent (<[email protected]> [InternalId=31288836753166, Hostname=FOOBAR1.namprd07.prod.outlook.com] 8924 bytes in 0.309, 28.142 KB/sec Queued mail for delivery)
Mar 19 06:10:26 ip-172-2-0-53 sendmail[28131]: v2JDA1k4028131: to=root, ctladdr=root (0/0), delay=00:20:15, xdelay=00:00:00, mailer=relay, pri=30580, relay=[127.0.0.1] [127.0.0.1], dsn=2.0.0, stat=Sent (v2JDAG5W028134 Message accepted for delivery)
并将其转换为
000015 Mar 19 06:10:16 delay=00:00:15
000003 Mar 19 14:41:26 delay=00:00:03
002015 Mar 19 06:10:26 delay=00:20:15
sed 正则表达式匹配
^\([A-Za-z]\{3\} \{1,2\}[0-9]\{1,2\} \{1,2\}\([0-9]\{2\}:\)\{2\}[0-9]\{2\}\).* \(delay=\([0-9]\{2\}\):\([0-9]\{2\}\):\([0-9]\{2\}\)\).*
我们首先显式匹配日期组件;稍后我们将需要它们来输出。然后,我们分别找到并匹配延迟及其时序组件;您想要输出的延迟。稍后我们将需要计时组件来进行排序。
sed 的正则表达式替换
\4\5\6 \1 \3
在正则表达式的替换方面,我们采用我们抓取的计时组件,并将它们连接起来,而不使用它们最初具有的“:”分隔符。这很重要,因为我们稍后将使用它们sort
。在计时组件之后,我们附加日期字符串和整个原始延迟字符串;分类后我们会想要它们。
种类
sort -nr
由于我们的输入现在以十进制数字而不是字符串时间戳开头,因此我们可以使用sort
的数字模式,并用-n
标志指定。
默认情况下,sort
按升序排序,将最大值放在最后。因为这意味着处理全部ofsort
的输出找到最大的 N 个值,我们使用 sort 的-r
标志来反转输出顺序;现在,将首先输出最大值,我们可以head
代替“tail”。
此时我们的输出如下所示:
002015 Mar 19 06:10:26 delay=00:20:15
000015 Mar 19 06:10:16 delay=00:00:15
000003 Mar 19 14:41:26 delay=00:00:03
头
head -n5
此时,我们的输入将首先具有最大值,并且我们已经知道我们需要最大的 5 个值。所以我们使用head
s-n
参数来告诉head
我们想要多少个值。
由于在本例中,我们实际上没有超过 5 个值,因此我们仍然可以获得输入的所有输出。
002015 Mar 19 06:10:26 delay=00:20:15
000015 Mar 19 06:10:16 delay=00:00:15
000003 Mar 19 14:41:26 delay=00:00:03
切
cut -d\ -f2-
由于我们不再需要它,因此我们需要删除sed
在第一步中插入的数字排序键。为此,我们转向cut
,它允许我们从提供的每一行中选择我们想要的字段。
我们使用 cut 的-d
参数来告诉它我们的字段分隔符、分隔符是什么。因为字段分隔符是空格,所以我们需要用 对其进行转义\
,得到-d\
。
从cut
的角度来看,这将行分解002015 Mar 19 06:10:26 delay=00:20:15
为002015
Mar
19
06:10:26
delay=00:20:15
.
为了指定我们想要的字段,我们使用-f
.由于我们想要除第一个字段之外的所有字段,因此我们使用-f2-
,为我们提供所需的输出:
Mar 19 06:10:26 delay=00:20:15
Mar 19 06:10:16 delay=00:00:15
Mar 19 14:41:26 delay=00:00:03
答案2
perl -lane '
print join $", /\sdelay=\K(\S+)(?=,)/, splice(@F, 0, 3), /\s\K(delay=\S+)(?=,)/;
' | sort -t: -k 1,1nr -k 2,2nr -k 3,3nr | cut -d\ -f2- | head -n 5