如何提取其他两个子串之间的子串?

How to extract substring between two other substrings?

我有一个脚本可以逐行读取日志文件。我需要提取两个子字符串之间的文本,如果它们存在于我的脚本当前正在读取的行中。

例如,如果一行有:

some random text here substring A abc/def/ghi substring B

我需要通过将 substring Asubstring B 之间的文本 abc/def/ghi 存储在变量中来提取它。我该怎么做?

我查看了这个 Extract substring in Bash 但找不到任何与我的用例完全匹配的内容。

我相信你能做到:

var="$(echo "some random text here substring A abc/def/ghi substring B"|grep -oP "substring A \K(.*) (?=\ substring B)")"

# which produces:
echo $var
abc/def/ghi

或者如果下面的grep更易读,更容易理解,也可以这样用:

grep -oP "(?<=substring\ A\ )(.*)(?=\ substring B)"

这和上面的逻辑本质上是一样的

如果 searched/matched 字符串是 2 个或更多单词,这也有效。


编辑 1:

现在我知道你是想通过提取文件的最后一行,然后进行正则表达式匹配来做到这一点? 你可以这样做:

var="$(tail -n1 file.txt|grep -oP "(?<=substring\ A\ )(.*)(?=\ substring B)")"

如果您确定此文件的最后一行始终与您原始问题中的模式相匹配..

Bash 提供 带子字符串移除的参数扩展 允许您从前面 trim 到 "substring A",然后 trim "substring B" 从后面离开 "abc/def/ghi"。例如,您可以这样做:

ssa="substring A"         ## substrings to find text between
ssb="substring B"

line="some random text here substring A abc/def/ghi substring B"

text="${line#*${ssa}}"    ## trim through $ssa from the front (left)
text="${text%${ssb}*}"    ## trim through $ssb from the back (right)

echo $text                ## output result

示例输出

abc/def/ghi

从字符串前面 trimming 和从字符串后面 trimming 的两种基本形式是:

${var#pattern}      # Strip shortest match of pattern from front of $var
${var##pattern}     # Strip longest match of pattern from front of $var
${var%pattern}      # Strip shortest match of pattern from back of $var
${var%%pattern}     # Strip longest match of pattern from back of $var

其中 pattern 可以包含通配符,例如 '*''?'。查看所有内容,如果您还有其他问题,请告诉我。

使用BASH_REMATCH

BASH_REMATCH是一个内部数组,包含匹配[[ text =~ REGEX ]]的结果。 ${BASH_REMATCH[0]}REGEX 匹配的总文本,然后 ${BASH_REMATCH[1..2..etc]} 是正则表达式中 (...) 之间的正则表达式捕获的匹配部分(您可以提供多个捕获)

使用上面相同的设置,您可以修改替换参数扩展使用的脚本 text 以使用

regex="^.*${ssa} ([^ ]+) ${ssb}.*$"   ## REGEX to match with (..) capture

[[ $line =~ $regex ]] && echo ${BASH_REMATCH[1]}

$regex 中的正则表达式将匹配捕获 $ssa$ssb 之间的整行。完整的修改脚本为:

ssa="substring A"         ## substrings to find text between
ssb="substring B"

line="some random text here substring A abc/def/ghi substring B"

regex="^.*${ssa} ([^ ]+) ${ssb}.*$"   ## REGEX to match with (..) capture

[[ $line =~ $regex ]] && echo ${BASH_REMATCH[1]}

(相同的输出)

这两种方法在 man 1 bash 中都有完整的解释。使用适合您所面临情况的任何一种。我总是发现参数扩展更直观(并且您可以逐渐将文本缩减为几乎任何您需要的内容)。但是,扩展正则表达式匹配的强大功能可以为参数扩展提供强大的替代方案。