bash regex将可选的子字符串与组分隔符匹配

时间:2019-01-17 09:52:14

标签: regex bash substring

基本上我想用以下格式解析日志条目:

  

a1 b2 c3)@ in#(d4 e5 f6)@ out#(g7 h8 i9

  1. )@in#(是前两个子字符串(a1 b2 c3d4 e5 f6)之间的第一个定界符。
  2. )@out#(g7 h8 i9可选定界符。
  3. 定界符周围存在一两个空格。

有趣的一点是,两个分隔符都包含多个 个字符。

我想使用Bash 正则表达式来获取所有子字符串。这是我当前的代码:

s1='a1 b2 c3 )@in#( d4 e5 f6 )@out#( g7 h8 i9'
s2='a1 b2 c3 )@in#( d4 e5 f6'

regex='^(.*)[[:space:]]+\)@in#\([[:space:]]+(.*)[[:space:]]+\)@out#\([[:space:]](.*)$'

[[ $s =~ $regex ]] && printf '%s\n%s\n%s\n%s\n' "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}

代码仅匹配s1,但不匹配。这就是为什么我写这篇文章来为您提供帮助的原因。

顺便说一句,任何人都可以澄清一下[[:space:]]\s之间的区别。


更新:从下面提供的评论和答案中,也许Bash正则表达式不适用于此处。 awk会更好。


我不仅要打印输出,还想将它们捕获到变量中或read捕获到数组中以进行进一步处理。

2 个答案:

答案 0 :(得分:0)

您可以尝试Perl

$ echo "a1 b2 c3 )@in#( d4 e5 f6 )@out#( g7 h8 i9" | perl -lne ' @a=split(/\s*\)\@in#\(\s*|\s*\)\@out#\(\s*/); print join("\n",@a) '
a1 b2 c3
d4 e5 f6
g7 h8 i9

$ echo "a1 b2 c3 )@in#( d4 e5 f6 g7 h8 i9" | perl -lne ' @a=split(/\s*\)\@in#\(\s*|\s*\)\@out#\(\s*/); print join("\n",@a) '
a1 b2 c3
d4 e5 f6 g7 h8 i9

$

您可以通过while循环读取输出

$ echo "a1 b2 c3 )@in#( d4 e5 f6 g7 h8 i9" | perl -lne ' @a=split(/\s*\)\@in#\(\s*|\s*\)\@out#\(\s*/); print join("\n",@a) ' | while read x;do; echo "val=$x"; done
val=a1 b2 c3
val=d4 e5 f6 g7 h8 i9
$

或在perl中打印每个arr值,然后一对一读取它们

$ echo "a1 b2 c3 )@in#( d4 e5 f6 g7 h8 i9" | perl -lne ' @a=split(/\s*\)\@in#\(\s*|\s*\)\@out#\(\s*/); print $a[0] ' | read x1
$ echo $x1
a1 b2 c3
$

$ echo "a1 b2 c3 )@in#( d4 e5 f6 g7 h8 i9" | perl -lne ' @a=split(/\s*\)\@in#\(\s*|\s*\)\@out#\(\s*/); print $a[1] ' | read x2
$ echo $x2
d4 e5 f6 g7 h8 i9
$

答案 1 :(得分:0)

我的最终解决方案如下:

IFS=$'\n' _log_array=( $( awk -F'[[:space:]]*\\)@(in|out)#\\([[:space:]]*' '{ print NF; for (i = 1; i <= NF; ++i) print $i; }' <<< $s ) )
  1. IFS设置为\n
  2. 我将输出分配给 array 。而不是打印到 stdout
  3. 注意外面多余的括号。

这里有两个参考文献:

  1. https://stackoverflow.com/a/21130572/2336707
  2. https://stackoverflow.com/a/42635720/2336707
相关问题