【问题标题】:How to extract substring between two other substrings?如何在其他两个子字符串之间提取子字符串?
【发布时间】:2022-01-26 04:02:22
【问题描述】:

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

例如,如果一行有:

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

我需要将abc/def/ghi 之间的文本提取出来,该文本位于substring Asubstring B 之间,方法是将其存储在一个变量中。我该怎么做呢?

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

【问题讨论】:

  • 尝试查看awk 和其他解释语言。

标签: bash shell substring


【解决方案1】:

Bash 提供带有子字符串删除的参数扩展,它允许您从前面修剪"substring A",然后从后面修剪"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

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

${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 中都有完整的解释。使用适合您所面临情况的任何一种。我总是发现参数扩展更直观一些(您可以逐步将文本缩减为您需要的任何内容)。然而,扩展正则表达式匹配的强大功能可以为参数扩展提供强大的替代方案。

【讨论】:

    【解决方案2】:

    我相信你可以做到:

    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)"
    

    这与上面的逻辑基本相同。

    如果搜索/匹配的字符串是 2 个或更多单词,这也将起作用。


    编辑 1:

    所以现在我了解到您正在尝试通过提取文件的最后一行,然后进行正则表达式匹配来做到这一点? 你可以这样做:

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

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

    【讨论】:

    • 对不起,我对 shell 脚本非常陌生。我正在尝试您发布的第二个命令。如何确保它应用于我正在阅读的日志文件的最后一行?
    • 是的,看起来我能够提取最后一行,但命令似乎不起作用:/
    • @RicardoFrancois 请提供有关如何提取最后一行的更多信息,或者输入文件最后的样子...如果您更改您的问题,显然解决方案也可以更改。展示您期望的结果......以及您已经尝试过的确切内容。
    • 该解决方案有效.. 您实施它的方式可能不适合您 ;)
    猜你喜欢
    • 1970-01-01
    • 2021-01-17
    • 2014-12-11
    • 1970-01-01
    • 2013-01-31
    • 2013-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多