正则表达式捕获整行,或者如果有可选字符,则还捕获2个捕获组

时间:2019-07-19 16:47:59

标签: regex bash sed

我想选择在可选字符之后捕获两个组。 我有2种可能的数据输出,如下所示:

Subject: 2019.07.19 13:30:00 some.host.com 178899 Problem: Server is unavailable
Subject: 2019.07.19 13:28:29 some.host.com 178892 Problem: Server is unavailable; Resolved: 2019.07.19 14:49:29

我的正则表达式过滤器如下:

"/Subject\: ([2-9]{1}[0-9]{3}\.[0-9]{2}\.[0-9]{2}) ([0-9]{2}\:[0-9]{2}\:[0-9]{2}) ([a-zA-Z0-9._-]*) ([0-9]*) Problem\: (.*)/"

到目前为止,它的工作方式如下:

\1 = 2019.07.19
\2 = 13:30:00
\3 = some.host.com
\4 = 178899
\5 = Server is unavailable

第二种模式:

\1 = 2019.07.19
\2 = 13:30:00
\3 = some.host.com
\4 = 178899
\5 = Server is unavailable; Resolved: 2019.07.19 14:49:29

我按如下方式使用此正则表达式过滤器:

echo  "$SUBJECT" | sed -E "s/Subject\: ([2-9]{1}[0-9]{3}\.[0-9]{2}\.[0-9]{2}) ([0-9]{2}\:[0-9]{2}\:[0-9]{2}) ([a-zA-Z0-9._-]*) ([0-9]*) Problem\: (.*)/\1\2\3\4\5/"

我想要的是\ 5组仅文本,直到可选的“;”字符,因此它将是“服务器不可用” 并且在可选“;”的情况下字符,然后同时捕获\ 6和\ 7以分别返回“ 2019.07.19”和“ 14:49:29”。

几个小时以来,我一直在尝试与非捕获组和可选组一起玩,但没有任何效果。

有人可以帮助我解决这一具有挑战性的问题吗?

更新:

PROBLEM_DATE=output[0]
PROBLEM_TIME=output[1]
PROBLEM_HOST=output[2]
PROBLEM_ID=output[3]
PROBLEM_DESC=output[4]
RESOLVED_DATE=output[5]
RESOLVED_TIME=output[6]

,然后可能会处理此数据,比较时间并写入日志文件。

Update2:

如果可以简化事情,我可以稍微调整一下数据格式。 是的,也许我在处理复杂的事情时,也许最好重新格式化:

Subject: 2019.07.19 13:30:00 some.host.com 178899 Problem: Server is unavailable
Subject: 2019.07.19 13:28:29 some.host.com 178892 Problem: Server is unavailable; Resolved: 2019.07.19 14:49:29

对此:

Subject: 2019.07.19 13:30:00 some.host.com 178899 Problem: Server is unavailable
Subject: 2019.07.19 14:49:29 some.host.com 178892 Resolved: Server is unavailable

我知道,我尝试做的方法不正确。

所以我想我可以将以下正则表达式与新数据格式一起使用:

"/Subject\: ([2-9]{1}[0-9]{3}\.[0-9]{2}\.[0-9]{2}) ([0-9]{2}\:[0-9]{2}\:[0-9]{2}) ([a-zA-Z0-9._-]*) ([0-9]*) (?:Problem|Resolved)\: (.*)/"

我不确定结构“(?:Problem | Resolved)”是否正确。

然后检查字符串是否包含单词“问题”或“已解决”以根据事件采取措施。

如果我将其分配给变量,sed不会给我数组输出吗? 我现在无法访问我的linux终端,因此无法检查。

3 个答案:

答案 0 :(得分:0)

这可能对您有用(GNU sed):

sed -E 's/^Subject: (....\...\...) (..:..:..) (\S+) (\S+) Problem: ([^;]*)(; Resolved: (....\...\...) (..:..:..))?.*/PROBLEM_DATE=\1\nPROBLEM_TIME=\2\nPROBLEM_HOST="\3"\nPROBLEM_ID=\4\nPROBLEM_DESC="\5"\nRESOLVED_DATE=\7\nRESOLVED_TIME=\8/' <<<"$SUBJECT" >srcFile
. scrFile

使用模式匹配和向后引用将所需结果输出到文件,然后将该文件作为源。

反向引用7和8分组在反向引用6中,后者是可选的(?)。

答案 1 :(得分:0)

我不确定我是否理解您的问题,但这就是您要尝试做的(使用GNU awk将第三个参数匹配到():

$ cat tst.awk
match($0,/Subject: ([2-9]{1}[0-9]{3}(\.[0-9]{2}){2}) ([0-9]{2}(:[0-9]{2}){2}) ([[:alnum:]._-]+) ([0-9]+) (Problem|Resolved): (.*)/,a) {
    print "PROBLEM_DATE="  a[1]
    print "PROBLEM_TIME="  a[3]
    print "PROBLEM_HOST="  a[5]
    print "PROBLEM_ID="    a[6]
    print "PROBLEM_STATE=" a[7]
    print "PROBLEM_DESC="  a[8]
    print "---"
}

$ awk -f tst.awk file
PROBLEM_DATE=2019.07.19
PROBLEM_TIME=13:30:00
PROBLEM_HOST=some.host.com
PROBLEM_ID=178899
PROBLEM_STATE=Problem
PROBLEM_DESC=Server is unavailable
---
PROBLEM_DATE=2019.07.19
PROBLEM_TIME=14:49:29
PROBLEM_HOST=some.host.com
PROBLEM_ID=178892
PROBLEM_STATE=Resolved
PROBLEM_DESC=Server is unavailable
---

以上操作是在此输入文件上执行的:

$ cat file
Subject: 2019.07.19 13:30:00 some.host.com 178899 Problem: Server is unavailable
Subject: 2019.07.19 14:49:29 some.host.com 178892 Resolved: Server is unavailable

您说过要比较时间戳,并根据结果将其写入日志文件-只需在awk中完成所有操作,请勿尝试在shell中进行操作。

答案 2 :(得分:-2)

我刚刚找到了解决方案。 sed输出配置为“ \ 1 | \ 2 | \ 3 |”它将产生一个定界的字符串,然后我将字符串简单地用“ |”分割字符以获取数组,可以将其与正确的数组成员计数进行比较,然后将它们分配给适当的变量以供以后进行可能的处理。

#!/bin/bash                                                                                                  

SUBJECT="Subject: 2019.07.19 13:30:00 some.host.com 178899 Problem: Server is unavailable"                   

OUTPUT=`echo "$SUBJECT" | sed -E 's/Subject\: ([2-9]{1}[0-9]{3}\.[0-9]{2}\.[0-9]{2}) ([0-9]{2}\:[0-9]{2}\:[0-
9]{2}) ([a-zA-Z0-9._-]*) ([0-9]*) Problem\: (.*)/\1|\2|\3|\4|\5|/'`                                          

echo "OUTPUT = $OUTPUT"                                                                                      

IFS='|'                                                                                                      
read -a RESULT <<< "$OUTPUT"                                                                                 

echo "${RESULT[0]}"                                                                                          
echo "${RESULT[1]}"                                                                                          
echo "${RESULT[2]}"                                                                                          
echo "${RESULT[3]}"                                                                                          
echo "${RESULT[4]}"  

输出:

sh-4.4$ ./test.sh                                                                                            
OUTPUT = 2019.07.19|13:30:00|some.host.com|178899|Server is unavailable|                                     
2019.07.19                                                                                                   
13:30:00                                                                                                     
some.host.com                                                                                                
178899                                                                                                       
Server is unavailable

Update-1:

按照建议将解释器从...更改为$(...),甚至更好-用双引号将它们引起来。

OUTPUT="$(echo "$SUBJECT" | sed -E 's/Subject\: ([2-9]{1}[0-9]{3}\.[0-9]{2}\.[0-9]{2}) ([0-9]{2}\:[0-9]{2}\:[
0-9]{2}) ([a-zA-Z0-9._-]*) ([0-9]*) Problem\: (.*)/\1|\2|\3|\4|\5|/')"

可以改进的是-用定界符|将字符串拆分为数组的方式。我现在正在寻找一种更好的方法,将尽快更新答案。

Update-2:

这是所需的解决方案。实际上有一个更大的脚本。这只是一部分。它可以正常工作并满足我的要求。

#!/bin/bash

SUBJECT="Subject: 2019.07.19 13:30:00 some.host.com 178899 Problem: Resolved: Server Problem:is unavailable"

OUTPUT="$(echo "$SUBJECT" | sed -E 's/Subject\: ([2-9]{1}[0-9]{3}\.[0-9]{2}\.[0-9]{2}) ([0-9]{2}\:[0-9]{2}\:[
0-9]{2}) ([a-zA-Z0-9._-]*) ([0-9]*) (Problem|Resolved)\: (.*)/\1|||\2|||\3|||\4|||\5|||\6/')"

IFS='|||'

read -a RESULT <<< "$OUTPUT"

if [ "${#RESULT[*]}" -eq '16' ];
then
  EVENT_DATE="${RESULT[0]}"
  EVENT_TIME="${RESULT[3]}"
  EVENT_HOST="${RESULT[6]}"
  EVENT_ID="${RESULT[9]}"
  EVENT_TYPE="${RESULT[12]}"
  EVENT_TEXT="${RESULT[15]}"

  echo "EVENT_DATE: $EVENT_DATE"
  echo "EVENT_TIME: $EVENT_TIME"
  echo "EVENT_HOST: $EVENT_HOST"
  echo "EVENT_ID:   $EVENT_ID"
  echo "EVENT_TYPE: $EVENT_TYPE"
  echo "EVENT_TEXT: $EVENT_TEXT"
fi

和输出:

EVENT_DATE: 2019.07.19
EVENT_TIME: 13:30:00
EVENT_HOST: some.host.com
EVENT_ID:   178899
EVENT_TYPE: Problem
EVENT_TEXT: Resolved: Server Problem:is unavailable