关于 bash:使用 awk 正则表达式后捕获日期

Capture date after regex using awk

我想打印正则表达式 "show memory compare.." 以及来自测试文件的日期。日期可以从一周中的任何一天开始。

问题

  • 无法弄清楚如何将星期几传递给 awk。它应该是数组格式吗?
    当前方法 (tr) 不替换为 OR (||),它只给出 (|),因此正则表达式替换不起作用。

尝试至今

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash

day_of_week=$(locale day | tr ';' '\
'
| cut -c 1-3 | tr '\
'
'||')

awk -v day_of_week="$day_of_week" '
/show memory compare start/,/^day_of_week/
/show memory compare end/,/^day_of_week/

'
testsnmpoutput.txt

TESTFILE (testsnmpoutput.txt)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
xr_lab#  show clock
Thu Sep 19 14:38:02.812 WIB
14:38:02.893 WIB Thu Sep 19 2019
xr_lab#
xr_lab#show memory compare start
Thu Sep 19 14:38:06.400 WIB
Successfully stored memory snapshot in /var/log/malloc_dump_memcmp_start.out
xr_lab#
xr_lab#
xr_lab#
xr_lab#show memory compare end
Thu Sep 19 14:40:56.123 WIB
xr_lab#show memory compare start
Thu Sep 19 14:46:28.464 WIB
Successfully stored memory snapshot in /var/log/malloc_dump_memcmp_start.out
xr_lab#
xr_lab#
xr_lab#
xr_lab#
xr_lab#show memory compare end
show memory compare report
show process memory
Thu Sep 19 14:50:10.422 WIB

期望的输出

1
2
3
4
5
6
7
8
xr_lab#show memory compare start
Thu Sep 19 14:38:06.400 WIB
xr_lab#show memory compare end
Thu Sep 19 14:40:56.123 WIB
xr_lab#show memory compare start
Thu Sep 19 14:46:28.464 WIB
xr_lab#show memory compare end
Thu Sep 19 14:50:10.422 WIB

谢谢。


这个oneliner应该做的:

1
$ grep -e 'show memory compare \\(start\\|end\\)' -e '^\\(Mon\\|Tue\\|Wed\\|Thu\\|Fri\\)' testsnmpoutput.txt | grep -A 1 'show memory compare' | grep -v '^--'

试试这个:

1
2
3
4
5
6
7
8
9
/show memory compare start|show memory compare end/ {
   print;
   while (getline != 0) {
      if (match($1,"Mon|Tue|Wed|Thu|Fri|Sat|Sun") != 0) {
        print;
        break;
      }
   }
}

此代码在包含"显示内存比较开始"或"显示内存比较结束"的行上运行,并从那里开始,遍历行以找出以星期几开始的第一行。

getline 读取输入的下一条记录并更新 $0 和 NF。


请您尝试以下操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
awk '
BEGIN{
  num=split("mon,tue,wed,thu,fri,sat,sun",array,",")
  for(k=1;k<=num;k++){
      days[array[k]]
  }
}
/show memory compare start/{
  found_start=1
  start=$0
  next
}
found_start && tolower($1) in days{
  print start ORS $0
  found_start=start=""
}
/show memory compare end/{
  found_end=1
  end=$0
  next
}
found_end && tolower($1) in days{
  print end ORS $0
  found_end=end=""
}
'
  Input_file

你可以使用

1
2
3
4
day_of_week=$(locale day | sed 's/\\([^;]\\{3\\}\\)[^;]*/\\1/g');
day_of_week="${day_of_week//;/|}";
p1='show memory compare (start|end)';
awk -v pat1="$p1" -v day_of_week="$day_of_week" '($0~pat1),($0~"^("day_of_week")"){ if ($0 ~ pat1 || $0 ~"^("day_of_week")") print $0; }' file

查看在线演示。

详情

  • $(locale day | sed 's/\\([^;]\\{3\\}\\)[^;]*/\\1/g'); - 获取以 ; 分隔的日期列表,并且只保留每天的 3 个首字母,删除其余的
  • "${day_of_week//;/|}" - 用 | 替换所有 ;
  • p1='show memory compare (start|end)' 定义包含起始范围模式(show memory compare startshow memory compare end)的 p1 变量
  • '($0~pat1),($0~"^("day_of_week")") 获取开始和结束模式之间的行范围(请注意,您不能将 /.../ 表示法与作为变量传递的正则表达式一起使用)
  • { if ($0 ~ pat1 || $0 ~"^("day_of_week")") print $0; } 仅打印与开始或结束模式匹配的行。

更多sed命令详情

sed 's/\\([^;]\\{3\\}\\)[^;]*/\\1/g' 命令使用 POSIX BRE 模式(因为没有 -E,也没有 -P 选项)匹配:

  • \\([^;]\\{3\\}\\) - 捕获组 1:

    • [^;]\\{3\\} - 除了 ; 之外的任何字符出现 3 次
  • [^;]* - ; 以外的 0 个或更多字符
  • \\1 - 匹配被替换为第 1 组的内容
  • g - 所有出现。

请参阅 POSIX ERE 模式版本演示 (sed -E 's/([^;]{3})[^;]*/\\1/g')。