【问题标题】:How to extract text between two patterns with sed/awk如何使用 sed/awk 在两个模式之间提取文本
【发布时间】:2019-09-24 08:18:57
【问题描述】:

我知道这个问题已经在这里被问了 1000 次,但是我阅读了很多类似的问题,但仍然没有找到正确的方法来解决这个问题。我需要从如下所示的行中提取一个数字:

{"version":"4.9.123M","info":{"version":[2034.2],"description":""},"status":"OK"}

预期输出:

2034.2

此版本号并不总是相同,但该行的其余部分应该。

我曾尝试使用 sed,但我是新手,但失败了:

 sed -e 's/version":[\(.*\),"description/\1/'

输出:

sed: -e expression #1, char 35: unterminated `s' command

我认为问题是该行涉及的特殊字符太多,我没有写好命令。

【问题讨论】:

  • 为什么不只是jq '.info.version[0]' file
  • 我不知道这个命令。它是如此简单,它正是我需要的。谢谢!
  • [ 是一个特殊的字符,它必须在正则表达式中转义。无论如何,即使您这样做,您的命令也不起作用。要解析 JSON,请使用 JSON 特定工具,例如 jq,以避免其他问题。

标签: shell awk sed grep


【解决方案1】:

因为它是 JSON,所以应该使用 JSON 感知工具来处理它。例如,如果您更喜欢 awk,则方法是使用 GNU awk 的 JSON 扩展。这是一个小方法。

首先下载并编译适当版本的 GNU awk、Gawkextlib 和 gawk-json。这很简单,实际上,只是./configuremake。然后,写一些代码:

awk '
@load "json"                                 # enable json extension
{
   lines=lines $0                            # read json file records and buffer to var lines
   if(json_fromJSON(lines,data)==1) {        # once the json is complete
       for(i in data["info"]["version"])     # that seems to be an array so all elements
           print data["info"]["version"][i]  # are outputed
       lines=""                              # once done with the first json object
   }                                         # reset the var for more lines
}' file

本次输出:

2034.2

解释一下:

JSON 文件结构可以从一行到多行不等,例如:

{"version":"4.9.123M","info":{"version":[2034.2],"description":""},"status":"OK"}

或:

{
  "version": "4.9.123M",
  "info": {
    "version": [
      2034.2
    ],
    "description": ""
  },
  "status": "OK"
}

所以我们需要用lines=lines $0 缓冲JSON 行,直到变量lines 中有一个完整的有效对象。我们使用扩展函数json_fromJSON() 来确定@​​987654332@ 中的有效性。验证后,对象被解开并存储到数组data。对于这个特定对象,数组的结构是:

data["version"]="4.9.123M"
data["info"]["version"][1]="2034.2"
data["info"]["description"]=""
data["status"]="OK"

我们可以使用这个递归数组扫描函数检查对象并产生一些输出:

awk '
@load "json"
function scan(a,p,    q) {           # a is array, p path to it, q is qnd *
    if(isarray(a))
        for(i in a) {
            q=p (p==""?"":"->") i
            scan(a[i],q)
        }
    else
        print p ":" a
}
{
   lines=lines $0
   if(json_fromJSON(lines,data)==1)
       scan(data)                    #
}' file.json

输出:

status:OK
version:4.9.123M
info->version->1:2034.2
info->description:

*) 又快又脏

以下是如何从数组中输出 JSON 的简短示例:https://stackoverflow.com/a/58109715/4162356

【讨论】:

  • @RavinderSingh13 我被大量的 json 所抛弃,我必须充分利用它。 :D。该文档几乎不存在。 Trial and err 主要是,但它只有两个函数和 json 存储到一个多维数组中。肯定胜过jq恕我直言。
  • 击败jq,然后考虑我:)(因为我在里面是假人:))让我回到家并尝试更多的实验,感谢 TON 再次分享这个:)
  • jq 有自己花哨的 DSL,这就是我们喜欢它的原因
  • @oguzismail 伙计,我和jq 一起哭了好几个晚上。最终安装了 MongoDB,这样我就不需要再使用它了。现在我从 gawk-json 开始。这就像沐浴在蜂蜜中。还有牛奶。和 awk。
  • @JamesBrown:哈哈!我看到你现在开始了一种趋势,带有awk 的 JSON 将在一段时间内成为“主流”
【解决方案2】:

如果版本总是用[]括起来,并且一行中没有其他[或],你可以试试这个逻辑

STR='{"version":"4.9.123M","info":{"version":[2034.2],"description":""},"status":"OK"}'
echo $STR | awk -F'[' '{print $2}' | awk -F']' '{print $1}'

【讨论】:

  • 很少你需要多个awk
【解决方案3】:

最简单的方法

当想要提取简单文本时尝试 grep

 echo "{"version":"4.9.123M","info":{"version":[2034.2],"description":""},"status":"OK"}"| grep -o "\[.*\]" | sed -e 's/\[\|\]//g'

【讨论】:

    【解决方案4】:

    应该这样做:

    STR='{"version":"4.9.123M","info":{"version":[2034.2],"description":""},"status":"OK"}'
    echo "$STR" | awk -F'[][]' '{print $2}'
    2034.2
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-20
      • 2014-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多