【问题标题】:editing a JSON file with sed使用 sed 编辑 JSON 文件
【发布时间】:2015-02-27 03:38:12
【问题描述】:

我需要编辑一个 JSON 文件,使用 sed,将一些数据添加到文件中。 JSON如下:

{
  'name':
  // more attributes that are already filled in 
}

我写了这个sed 命令来尝试一下:

sed "s/(\'name\':)/\1\"hello\"\,/g" /path/to/file.json

但是,我不断收到此错误:

sed: \1 not defined in the RE

预期结果是:

{
  'name': "hello",
  // more attributes here, left untouched
}

我知道这是一种不好的做法,但我认为我无法使用诸如 jq 之类的工具,因为该文件将在服务器上进行编辑,而我无法在服务器上安装 jq .如果有人有更好的解决方案,我很想听听。谢谢!

【问题讨论】:

  • 对于级联语言(如 JSON),最好永远不要使用正则表达式,而是使用上下文无关语法,甚至更好:特定语言工具。尤其是如果您希望您的工具可靠,这确实是一种不好的做法:最终它总会以某种方式出错。
  • 正如您所说,这是一种不好的做法。 jq 可以按原样下载并在没有依赖关系的情况下执行
  • 你需要转义冒号吗?可能值得一试。
  • 同意上面关于不使用 sed 的观点,但并非所有 seds 都以相同的方式工作。您可能需要使用's/\(\'name\':\)/\1....'。祝你好运。

标签: regex json bash sed


【解决方案1】:

你的反斜杠在错误的地方。 ' 不需要转义,但括号可以。这有效:

sed "s/\('name':\)/\1\"hello\"\,/g" /path/to/file.json

注意:我假设 file.json 不是一个 json 文件,而是一个特制的模板,否则这种替换没有任何意义(结果不会是 JSON)。使用 sed 处理 JSON 文件肯定是个坏主意,所以如果您尝试修改 JSON 而不是生成它,请查看jq 左右。

【讨论】:

  • 不要使用正则表达式解析 JSON!
  • 如果 file.json 是 JSON 文件,则生成的文件不会是 JSON。我认为他正在开发一个特定于用例的模板,以使其正常。
  • 感谢 Wintermute,这太棒了。对反斜杠有点困惑! @sputnick,我理解这些担忧,我也有点不安,但这不是一个重要的文件,如果出现问题,这不是一个大问题。我查看了 jq 但在这种情况下使用它是不切实际的。
  • 答案不只是给你,问题/答案有自己的生命,如果接受不良做法,使用搜索引擎搜索的人会选择不良做法。
  • 我添加了一些内容以使其清楚。但是,如果输出文件是有效的 JSON,那么输入文件不能是有效的 JSON,因此“使用 JSON 工具”对这个问题没有帮助。
【解决方案2】:

正如您所说,sed 不是这里的正确工具,而是使用适当的 JSON 解析器:

输入 json

$ cat json
{
  "name": "foobar"
}

使用:

$ jq '.name |= "qux"' json | tee json 

(最新 处理小文件)

或使用:

perl -i -MJSON -0ne '
    my $DS = decode_json $_;
    $DS->{name} = "qux";
    print encode_json $DS
' json

如果您想在不编辑文件的情况下测试命令,请删除-i 开关就地

输出 json

$ cat json
{
  "name": "qux"
}

【讨论】:

  • 感谢 sputnick 的回答,将尝试在我的系统中实现这一点,它看起来比使用 sed 好得多,我只是不确定替代方案。
【解决方案3】:

使用 python,它在大多数 POSIX 系统上都容易得多:

#!/usr/bin/python
import json
jsonObject = json.load(filename)
jsonObject['name'] = "hello"
json.dump(filename, jsonObject)

然后运行它:

python parse_json.py

编辑:要在 bash 设置中使用它,请使用此处的文档:

#!/bin/sh

# ...

# set the name variable to something
name=VALUE

# ...

# and use it in a here document
parse_json_script=$(mktemp parse_json.XXXX.py)
cat > $parse_json_script << SCRIPT
#!/usr/bin/env python
import json
jsonObject = json.load(filename)
# You can use bash variables in here documents.
# the line below uses the bash variable `name` and inserts it into the python script
jsonObject['name'] = "$name"
print(jsonObject['name'])
json.dump(filename, jsonObject)
SCRIPT
python $parse_json_script && rm $parse_json_script

上述脚本使用here文档动态创建python脚本并运行它以更改JSON,然后删除解析json脚本。

不过,我个人更喜欢使用python的sh模块,只用python编写脚本:

#!/usr/bin/python
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals 
import sh

# now you can call any command as if it were a python function
sh.ls("-lah") # `ls -lah`, but maybe you use python's `os` module instead
sh.rsync("-avHAX","foo","bar")

在python的sh(命令执行)、os(文件操作)、shutil(递归文件操作)和re(正则表达式)模块之间,我发现bash的功能通常可能会被完全替换。

【讨论】:

  • 一直在探索这个选项,它似乎工作得很好,但是,我需要在一个更大的 Bash 脚本中运行它,"hello" 值实际上是一个 Bash 变量。如何结合 Bash 和 Python?
  • 我已将您要求的内容添加到答案中。
  • 感谢添加,它工作得很好:) 我不得不稍微编辑你的 Python 让它在我的系统上工作:import jsonwith open('package.json', 'r+') as f:data = json.load(f)data["name"] = "$newstring"@987654335 @json.dump(data, f, indent=4)
【解决方案4】:
sed "s/'name':/& \"hello\",/" File

与 Wintermutes 的答案几乎相似,但在这里我们避免使用 (grouping),因此我们使用 &amp; (pattern matched) 而不是 \1。此外,如果每行仅出现一次'name':,则不需要global substitution (g)。我不确定 sed 是否适合这项工作。我还不知道 JSON。 :-)

【讨论】:

    猜你喜欢
    • 2011-12-17
    • 2011-05-26
    • 2022-07-12
    • 2016-02-19
    • 2012-04-19
    • 1970-01-01
    • 2010-10-17
    • 2015-01-12
    • 2012-09-23
    相关资源
    最近更新 更多