将部分匹配模式保存到变量

时间:2010-04-12 18:15:11

标签: regex bash variables extraction

我想提取一个匹配模式的子字符串并将其保存到文件中。示例字符串:

Apr 12 19:24:17 PC_NMG kernel: sd 11:0:0:0: [sdf] Attached SCSI removable disk

我想在括号之间提取部分,在本例中为[sdf]

我尝试执行grep -e '[$subtext]'之类的操作,将括号中的文本保存到变量中。当然它不起作用,但我正在寻找类似于此的方法。在这样的正则表达式中包含变量会非常优雅。我能做什么最好?

谢谢!

4 个答案:

答案 0 :(得分:11)

BASH_REMATCH是一个包含与shell匹配的组的数组。

$ line='Apr 12 19:24:17 PC_NMG kernel: sd 11:0:0:0: [sdf] Attached SCSI removable disk'
$ [[ $line =~ \[([^]]+)\] ]]; echo "${BASH_REMATCH[1]}"
sdf

如果你想把它放在一个循环中,你可以这样做;这是一个例子:

while read -r line; do
  if [[ $line =~ \[([^]]+)\] ]] ; then
    drive="${BASH_REMATCH[1]}"
    do_something_with "$drive"
  fi
done < <(dmesg | egrep '\[([hsv]d[^]]+)\]')

这种方法不会将外部调用放入循环中 - 因此shell不需要forkexec来启动外部程序,例如sedgrep 。因此,它可以说比这里提供的其他方法更清晰。

顺便说一句,你最初的方法(使用grep)并不是那么遥远;使用grep -o将仅输出匹配的子字符串:

$ subtext=$(egrep -o "\[[^]]*\]" <<<"$line")

...虽然这包括捕获中的括号,因此不是100%正确。

答案 1 :(得分:9)

可能有更好的方法只使用bash,但是:

echo 'Apr 12 19:24:17 PC_NMG kernel: sd 11:0:0:0: [sdf] Attached SCSI removable disk' \
| sed -s 's/.*\[\(.*\)\].*/\1/'

正如约根所指出的,这与不匹配的线匹配。如果您不想输出不匹配的行,请使用'-n'以使其不输出模式,并使用'/ p'在匹配时输出模式。

| sed -n 's/.*\[\(.*\)\].*/\1/p'

答案 2 :(得分:4)

与正则表达式匹配,使用分组替换,仅在正则表达式匹配时打印:

sed -n "s/.*\[\(.*\)\].*/\1/p"

答案 3 :(得分:0)

sed是贪婪的,所以如果您的数据中有更多[]对,则sed答案会错过部分数据。使用grep + tr解决方案,或者您可以使用awk

$ cat file
[sss]Apr 12 19:24:17 PC_NMG kernel: sd 11:0:0:0: [sdf] Attached SCSI removable disk [tag] blah blah

$ awk -F"[" '{for(i=2;i<=NF;i++){if($i~/\]/){sub("].*","",$i)};print $i}}' file
sss
sdf
tag