Regex 使用正则表达式从字符串中减去值

Regex 使用正则表达式从字符串中减去值,regex,awk,grep,Regex,Awk,Grep,有一些日志文件 $> cat ./text Tue, 28 Feb 2012 15:43:20 407a3f8bbf704e41bef1f4c0ac24f310 FAILED Tue, 2012 15:45:10 525b13aed6094417a56fd7bc67a10ad7 FAILED Tue, 28 Feb 2012 15:47:08 ae3e2dc3e5b14d0eb7338ab308a32c8e Tue, Feb 2012 15:52:26 18486cbede4e4cb4be

有一些日志文件

$> cat ./text
Tue, 28 Feb 2012 15:43:20 407a3f8bbf704e41bef1f4c0ac24f310 FAILED
Tue, 2012 15:45:10 525b13aed6094417a56fd7bc67a10ad7 FAILED
Tue, 28 Feb 2012 15:47:08 ae3e2dc3e5b14d0eb7338ab308a32c8e
Tue, Feb 2012 15:52:26 18486cbede4e4cb4bee931bf29823dda FAILED
Tue, 28 Feb 2012 15:54:17 3c96983a68dd4c5e968dcad512bf77e9 FAILED
Tue, Feb 2012 15:56:30 2191e5260aa44a2a8997c47d710d6fbb FAILED
Tue, 28 Feb 2012 15:58:25 083fc56361414695b4e5cf54f8c57a9e FAILED
28 Feb 2012 16:01:55 5cbad64d2d62429c97ed7fdf98087c44 FAILED
Tue, 28 Feb 2012 16:03:37 a0d33b998b8247ffbecb984198453c0b
28 Feb 2012 16:05:32 cf9c1893e8b64aa89636a8cfeff56cf2 FAILED
Tue, 28 Feb 2012 16:06:53 027d99f7fa68436d9000661a7af07e2a PASSED
使用
grep
很容易获得所有十六进制值

$> grep --only-matching --perl-regex "[0-9a-f]{32}" ./text
407a3f8bbf704e41bef1f4c0ac24f310
525b13aed6094417a56fd7bc67a10ad7
ae3e2dc3e5b14d0eb7338ab308a32c8e
18486cbede4e4cb4bee931bf29823dda
3c96983a68dd4c5e968dcad512bf77e9
2191e5260aa44a2a8997c47d710d6fbb
083fc56361414695b4e5cf54f8c57a9e
5cbad64d2d62429c97ed7fdf98087c44
a0d33b998b8247ffbecb984198453c0b
cf9c1893e8b64aa89636a8cfeff56cf2
027d99f7fa68436d9000661a7af07e2a
但是我如何使用
awk

所以实际的问题是:我怎样才能从给定的字符串中减去一些匹配正则表达式的值呢?例如,在
awk
源文件的某一行上,我有$0值,这实际上是整个字符串,如
“Tue,Feb 2012 15:56:30 2191e5260aa44a2a8997c47d710d6fbb FAILED”
。我正在寻找一些
awk
命令来获得十六进制值,比如:

 hex = command_name( $0, "[0-9a-f]{32}" )
hex
将等于
2191e5260aa44a2a8997c47d710d6fbb


我该怎么做?

原始的
awk
程序不支持regex replace中的反向引用。如果幸运的话,您可以访问GNU awk,您可以使用
sub()
函数提取字符串的部分内容。理论上它是这样工作的:

hex = sub(/^.* ([0-9a-fA-F]+) .*$/, "\1");

因为我现在手头没有GNU awk,所以您必须四处寻找正确的语法(例如,
“\1”
“\\1”
+
{32,32}
等等)。

也许您可以尝试GNU扩展
gensub()

您可以为此使用match()(可能需要-re interval使用gawk):

非GNU awk答案

awk '
  {
    for (i=NF; i>0; i--)
      if (length($i)==32 && ! match($i,/[^0-9a-fA-F]/)) {
        hexvalue = $i
        break  # if you only expect one per line
      }
    print hexvalue    # or do something else
  }
'
这可能有效,或者您:

awk --re-interval -vRS='[0-9a-fA-F]{32}' 'RT{print RT}' file

如果日志文件的结构与所示示例一致:

awk '{print $6}' ./text

为什么你需要awk,而grep完全可以提取它?@Shiplu也许他想在awk中对字符串进行进一步的文本处理,而不需要创建一个管道链来完成awk所能做的事情。这个答案,原始问题和大多数其他答案都假设数据中的十六进制数正好是32个字符,而不确保它是。一种方法是:
/(^[xdigit:][^[:xdigit:][])[:xdigit:][]{32}([^[:xdigit:][].$)
awk --re-interval -vRS='[0-9a-fA-F]{32}' 'RT{print RT}' file
awk '{print $6}' ./text