【问题标题】:awk (or sed/grep) to get occurrences of substringawk(或 sed/grep)获取子字符串的出现
【发布时间】:2019-04-10 21:31:03
【问题描述】:

我在 bash 变量中有一个 json 字符串,它是这样的:

{
    "items": [
      {
        "foo": null,
        "timestamp": 1553703000,
        "bar": 123
      },
      {
        "foo": null,
        "timestamp": 1553703200,
        "bar": 456
      },
      {
        "foo": null,
        "timestamp": 1553703400,
        "bar": 789
      }
    ]
}

我想知道有多少timestamps 在给定的日期时间之后,所以如果我有1553703100,它将返回2

(如果你能得到我这个数字,就可以获得额外的虚数!)

作为实现这一目标的一步,我只想在字符串中获取 "timestamp": \d+, 的匹配项,以便我可以在 bash 脚本中循环它们。

我使用了一些 sed 和 grep,但从未使用过 awk,从我的阅读来看,这似乎更适合这项任务。

其他信息: - 如上所述,json 已经打印得很漂亮,所以时间戳总是在不同的行上。 - 这是在 Cygwin 中运行的,所以我有 awk/gawk、sed 和 grep/egrep,但可能没有其他人。 - 可以是 json 中任意数量的时间戳。

【问题讨论】:

  • 使用'jq'解析JSON
  • @GillesQuenot,OP 指定了可用的工具
  • jq 在 cygwin 上可用。
  • 我不知道如何使用jq,因为每个人都忙着告诉我使用它,以至于他们忘记了用它发布实际的解决方案。
  • 谢谢大家!两个答案都很棒。原来我没有安装jq,所以我将使用 awk 解决方案。希望我可以将 2 个答案标记为已接受:-(

标签: regex bash awk sed grep


【解决方案1】:

你没有提供预期的输出,所以这是一个猜测,但这是你想要做的吗?

$ echo "$var" | jq '.items[].timestamp'
1553703000
1553703200
1553703400

或者也许:

$ echo "$var" | jq '.items[].timestamp | select(. > 1553703100)'
1553703200
1553703400

或:

$ echo "$var" | jq '[.items[].timestamp | select(. > 1553703100)] | length'
2

警告:我只是在学习jq,所以可能有更好的方法来完成上述操作!

【讨论】:

  • 很好,谢谢。 OP 指定他想要大于指定时间戳的记录数。在jq 有什么方法可以做到这一点?
  • @vintnes 我在 Google 上搜索了几个 jq 示例并根据它们更新了我的答案。
【解决方案2】:

edit:下面列出的第二种方法存在严重的问题,@EdMorton 非常有帮助地概述了这些问题。我选择保留旧代码用于教育目的。

避开substr(),捕获空字符串i

$ awk -v dt=1553703100 '
  /timestamp/ && $2+0>dt {i++}
  END {print i+0}
' <<< "$var"

2

警告:有问题的代码

在这里,我使用substr(string, index, [characters]) 修剪第二个字段的逗号。 /timestamp/ 正则表达式并不复杂;如果你的 json 变得更复杂,它可以得到改进。

$ awk -v dt=1553703100 '
  /timestamp/ && substr($2, 0, length($2)) > dt {i++} 
  END {print i}
' <<< "$var"

2

【讨论】:

  • substr() 的第二个参数是子字符串的起始位置。 awk 中的所有数组索引、字段和字符串都从 1 开始,而不是 0。当您使用 0 作为 substr() 的第二个参数时,awk 会像对待任何其他无效值一样对待它(尝试 awk 'BEGIN{print substr("bananas",-27,3)}')并处理它就好像您指定了 1 一样。第三个参数是您希望 substr 有多长。使用length($2) 与将该字段留空相同,因为它将为您提供字符串的完整长度。 ITYM substr($2, 1, length($2)-1) 但您可以改为使用 $2+0 剥离 ,
  • 最终的打印结果应该是print i+0,这样即使没有匹配的值,你也会得到一个数字输出(与这种情况下的空字符串输出相反)。
【解决方案3】:

您还可以快速实施python 解决方案:

输入

$ cat data.json 
{
    "items": [
      {
        "foo": null,
        "timestamp": 1553703000,
        "bar": 123
      },
      {
        "foo": null,
        "timestamp": 1553703200,
        "bar": 456
      },
      {
        "foo": null,
        "timestamp": 1553703400,
        "bar": 789
      }
    ]
}

代码

$ cat extract_value2.py 
import json

tLimit = 1553703100
with open('data.json') as f:
    data = json.load(f)
    print([t['timestamp'] for t in data["items"] if t['timestamp'] > tLimit])

输出

$ python extract_value2.py 
[1553703200, 1553703400]

计数代码:

$ cat extract_value2.py 
import json

tLimit = 1553703100
with open('data.json') as f:
    data = json.load(f)
    print(len([t['timestamp'] for t in data["items"] if t['timestamp'] > tLimit]))

输出

$ python extract_value2.py
2 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-01
    • 2019-10-20
    • 2019-01-08
    • 2021-06-19
    • 1970-01-01
    • 1970-01-01
    • 2019-08-11
    相关资源
    最近更新 更多