我想提取一个匹配模式的子字符串并将其保存到文件中。示例字符串:
Apr 12 19:24:17 PC_NMG kernel: sd 11:0:0:0: [sdf] Attached SCSI removable disk
我想在括号之间提取部分,在本例中为[sdf]
。
我尝试执行grep -e '[$subtext]'
之类的操作,将括号中的文本保存到变量中。当然它不起作用,但我正在寻找类似于此的方法。在这样的正则表达式中包含变量会非常优雅。我能做什么最好?
谢谢!
答案 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不需要fork
和exec
来启动外部程序,例如sed
或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