在同一行的两个位置使用 sed 或 awk 从多行中删除图案



我有一个包含 12,166,466 行的 JSON 文件。 我想从键上的值中删除引号:"timestamp": "1538564256","score": "10",看起来像"timestamp": 1538564256,"score": 10,.

输入:

{
"title": "DNS domain", ,
"timestamp": "1538564256",
"domain": {
"dns": [
"www.google.com"
]
},
"score": "10",
"link": "www.bit.ky/sdasd/asddsa"
"id": "c-1eOWYB9XD0VZRJuWL6"
}, {
"title": "DNS domain",
"timestamp": "1538564256",
"domain": {
"dns": [
"google.de"
]
},
"score": "10",
"link": "www.bit.ky/sdasd/asddsa",
"id": "du1eOWYB9XD0VZRJuWL6"
}
}

预期产出:

{
"title": "DNS domain", ,
"timestamp": 1538564256,
"domain": {
"dns": [
"www.google.com"
]
},
"score": 10,
"link": "www.bit.ky/sdasd/asddsa"
"id": "c-1eOWYB9XD0VZRJuWL6"
}, {
"title": "DNS domain",
"timestamp": 1538564256,
"domain": {
"dns": [
"google.de"
]
},
**"score": 10,**
"link": "www.bit.ky/sdasd/asddsa",
"id": "du1eOWYB9XD0VZRJuWL6"
}
}

我试过:

sed -E '
s/"timestamp": "/"timestamp": /g
s/"score": "/"score": /g
'

第一部分非常简单,但是如何删除包含"时间戳"和"分数"的行尾的"?我如何使用 sed 甚至 awk 或其他工具访问它,因为我有 1200 万行要处理?

假设您像这样修复 JSON 输入文件:

<file jq .
[
{
"title": "DNS domain",
"timestamp": "1538564256",
"domain": {
"dns": [
"www.google.com"
]
},
"score": "10",
"link": "www.bit.ky/sdasd/asddsa",
"id": "c-1eOWYB9XD0VZRJuWL6"
},
{
"title": "DNS domain",
"timestamp": "1538564256",
"domain": {
"dns": [
"google.de"
]
},
"score": "10",
"link": "www.bit.ky/sdasd/asddsa",
"id": "du1eOWYB9XD0VZRJuWL6"
}
]

您可以使用jq及其tonumber函数将所需的字符串更改为值:

<file jq '.[].timestamp |= tonumber | .[].score |= tonumber'

如果 JSON 结构与您的示例大致匹配(例如,"timestamp"、冒号和值之间不会有任何其他空格字符(,那么这个 awk 应该没问题。如果可用,使用jq进行 JSON 转换是迄今为止更好的选择!

awk '{print gensub(/("(timestamp|score)": )"([0-9]+)"/, "\1\3", "g")}' file
  1. 请注意,tonumber可能会失去精度。 如果不允许使用tonumber,并且输出是由 jq 生成的(或以其他方式垂直线性化(,那么按照本页其他地方的建议使用 awk 是一个不错的方法。 (如果你的awk没有gensub,那么awk程序可以很容易地适应。这是使用sed的相同事情,假设其扩展正则表达式处理的标志是-E

    sed -E -e 's/"(timestamp|score)": "([0-9]+)"/"1": 2/'

  2. 作为参考,如果对相关键的位置有任何疑问,这里有一个 jq 中的过滤器,它对此是不可知的:

    walk(if type == "object" then if has("timestamp") then .timestamp|=tonumber else . end | if has("score") then .score|=tonumber else end else . end)

如果你的jq没有walk/1,那么只需从网络上获取其def,例如从 https://raw.githubusercontent.com/stedolan/jq/master/src/builtin.jq

  1. 如果要将所有数字值字符串转换为数字,可以编写:

    walk(if type=="object" then map_values(tonumber? // .) else . end)

这可能对你有用(GNU sed(:

sed ':a;/"timestamp":s*"1538564256",/{s/"//3g;:b;n;/timestamp/ba;/"score":s*"10"/s/"//3g;Tb}' file

遇到包含"timestamp": "1538564256",的行时,请删除第 3 个或更多"。然后继续阅读,直到另一行包含timestamp和重复或包含"score": "10的行,并删除第 3 个或更多"

最新更新