【问题标题】:Replace pattern with part of matched string from the sameline in bash用bash中同一行中匹配字符串的一部分替换模式
【发布时间】:2017-10-09 08:45:56
【问题描述】:

我有一个文件,每行一个 json,格式如下:

{"id":13, "url":"https://sub.domain.com/path", "dm":"-", "ip":"192.168.0.1"}
{"id":14, "url":"sub.domain2.com/?param=value", "dm":"-", "ip":"192.168.0.1"}
{"id":15, "url":"domain.com/path", "dm":"prefilled.com", "ip":"192.168.0.1"}

我需要用同一行中的相应域替换“dm”:“-”以获得此输出:

{"id":13, "url":"https://sub.domain.com/path", "dm":"sub.domain.com", "ip":"192.168.0.1"}
{"id":14, "url":"sub.domain2.com/?param=value", "dm":"sub.domain2.com", "ip":"192.168.0.1"}
{"id":15, "url":"domain.com/path", "dm":"prefilled.com", "ip":"192.168.0.1"}

任何 bash 命令仅适用于具有 "dm":"-" 的行,因为文件长度超过 10k 行

【问题讨论】:

  • 您考虑过使用jq 吗?
  • 我现在正在调查。我已编辑问题以反映该文件是 json 事件的日志,每行一个。

标签: json awk sed stream jq


【解决方案1】:

使用 GNU 或 OSX sed 通过-E 支持 ERE:

$ sed -E 's#(.*"url":"([^"]+\/\/)?([^"/]+).*"dm":")-"#\1\3"#' file
{"id":13, "url":"https://sub.domain.com/path", "dm":"sub.domain.com", "ip":"192.168.0.1"}
{"id":14, "url":"sub.domain2.com/?param=value", "dm":"sub.domain2.com", "ip":"192.168.0.1"}
{"id":15, "url":"domain.com/path", "dm":"domain.com", "ip":"192.168.0.1"}

使用 GNU awk 将第三个参数匹配():

$ awk 'match($0,/(.*"url":"([^"]+\/\/)?([^"/]+).*"dm":")-(".*)/,a){$0=a[1] a[3] a[4]} 1' file
{"id":13, "url":"https://sub.domain.com/path", "dm":"sub.domain.com", "ip":"192.168.0.1"}
{"id":14, "url":"sub.domain2.com/?param=value", "dm":"sub.domain2.com", "ip":"192.168.0.1"}
{"id":15, "url":"domain.com/path", "dm":"domain.com", "ip":"192.168.0.1"}

【讨论】:

  • 这行得通!但是有一个问题,如何仅对具有 "dm":"-" 的行执行此操作?
  • 感谢您的支持。我编辑了问题以反映接受的答案。
  • 有效。为那个教了我很多关于awk 的人加上一个(希望一旦你会像我一样喜欢jq ;))
  • 谢谢!到目前为止,我个人还没有在 json 中遇到任何我需要从命令行解析的东西,但我确信有一天.....当然希望到那时会有一个 gawk 库:- )。
【解决方案2】:

使用jq-1.5(atm 的最新版本),您可以:

jq 'if .dm == "-" then .dm = (.url|sub("https?://";"")|sub("/.*";"")) else . end' a.json

解释:

if .dm == "-" ...           # Runs the following only if .dm exists and it's value is "-"
.dm=(...)                   # Assigns to .dm
.url|sub("^https?://"; "")  # Takes .url and replaces http/https:// from the beginning
...|sub("/.*"; "")          # Replaces everything after the first / (including it)

【讨论】:

  • 看起来 OP 有一个隐藏的要求,请参阅他在 my answer 下的评论:how to do it only for the lines which have "dm":"-"jq 看起来像什么?
  • 只是在寻找 jq 的好方法。实际上我正要推荐 Python,这是 imo 在 Linux 终端上最干净的方法。给我一些时间。
  • 好的,我真的很想看看jq 是否/如何处理这个问题。
  • 我认为是这样的: jq 'map(select(.dm == "-") | .dm = (.url|sub("^https?://";"" )|s​​ub("/.*";"")))' a.json
  • @Jinxmcg:如果您希望在命令行上对 json 数据进行操作, 答案应该始终涉及jq,它就是为此而设计的。跨度>
【解决方案3】:

你可以使用 sed 来做,但如果格式有任何变化,我建议你使用能够真正理解数据的东西:

sed -i -r 's/^(.*"url":")(.*\/\/)?(.*)(\/.*)"-"/\1\2\3\4"\3"/g' your_file

【讨论】:

  • .*? 应该是什么意思?如果它打算进行某种环顾,sed 不支持它们。
  • sed 带有扩展的正则表达式标志应该支持非贪婪匹配。刚刚对其进行了测试,它按预期工作。
  • 不,非贪婪匹配不是 ERE 的一部分,它是 PCRE 的一部分,没有 sed 支持。如果你得到了你期望的输出,那是因为其他原因。
  • 说得太早了......你是对的,但是对于有问题的文件内容,贪婪匹配会起作用。
猜你喜欢
  • 2012-10-13
  • 2014-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-26
  • 2014-12-27
  • 2020-03-13
  • 1970-01-01
相关资源
最近更新 更多