通过bash脚本更改json文件

时间:2014-07-24 19:58:40

标签: json bash

我需要你的帮助来解决以下问题: 我有一个看起来像这样的JSON文件:

{
  "key1": "value1",
  "key2": "value2",
  "key3": "value3"
}

如何通过bash脚本添加和删除新密钥(即"key4": "value4")? 我还看到在添加或删除新文件之前添加或删除文件中最后一个键末尾的逗号的问题。

谢谢

6 个答案:

答案 0 :(得分:80)

最好的选择是使用JSON CLI ,例如 jq

  • 在基于Debian的系统(如Ubuntu)上,您可以通过sudo apt-get install jq
  • 安装它
  • 在安装了Homebrew(http://brew.sh/)的macOS上,使用brew install jq

示例,基于以下输入字符串 - 输出到stdout

jsonStr='{ "key1": "value1", "key2": "value2", "key3": "value3" }'

删除" key3":

jq 'del(.key3)' <<<"$jsonStr"

添加属性&#34; key4&#34;值&#34; value4&#34;:

jq '. + { "key4": "value4" }' <<<"$jsonStr"

更改现有属性的值&#34; key1&#34;到&#34; new-value1&#34;:

jq '.key1 = "new-value1"' <<<"$jsonStr"

更强大的替代谢谢,Lars Kiesow
如果您使用--arg传递新值,则jq会正确转义该值:

jq '.key1 = $newVal' --arg newVal '3 " of rain' <<<"$jsonStr"

如果您想更新JSON文件(从概念上讲),请使用删除&#34; key3&#34;的示例:

# Create test file.
echo '{ "key1": "value1", "key2": "value2", "key3": "value3" }' > test.json

# Remove "key3" and write results back to test.json (recreate it with result).
jq -c 'del(.key3)' test.json > tmp.$$.json && mv tmp.$$.json test.json

您无法直接替换输入文件,因此会将结果写入临时文件,以便在成功时替换输入文件。

注意-c选项,它生成紧凑而不是漂亮的JSON。

对于所有选项和命令,请参阅http://stedolan.github.io/jq/manual/上的手册

答案 1 :(得分:23)

不是每个人的答案,但如果您已经在系统中安装了NodeJ,则可以使用它轻松操作JSON。

例如:

#!/usr/bin/env bash
jsonFile=$1;

node > out_${jsonFile} <<EOF
//Read data
var data = require('./${jsonFile}');

//Manipulate data
delete data.key3
data.key4 = 'new value!';

//Output data
console.log(JSON.stringify(data));

EOF

哎呀,如果需要进行JSON操作并且你有节点(即:你真的不需要任何其他bash功能),你可以使用node作为解释器直接编写脚本:

#! /usr/bin/env node
var data = require('./'+ process.argv[2]);
/*manipulate*/
console.log(JSON.stringify(data));

答案 2 :(得分:2)

要在适当位置更改文件,请使用sponge命令,例如

cat file.json | jq '.path.to.key = $v' --arg v 'new value' | sponge file.json

答案 3 :(得分:0)

基于Lenny的答案,我们可以使用node的-p选项,该选项评估给定脚本并将输出写入stdout

使用传播算子进行简单修改可以得出:

node -p "JSON.stringify({...require('./data.json'), key4: 'value4'}, null, 2)" > data.json

答案 4 :(得分:0)

如何通过bash脚本添加和删除新密钥(即"key4": "value4")?

使用专用的JSON工具(例如Xidel)比使用纯Bash函数更好。

添加新的属性值对:

点符号:

echo '{"a":1,"b":2,"c":3}' | xidel -s - -e '($json).d:=4'
{
  "d": 4,
  "a": 1,
  "b": 2,
  "c": 3
}

JSONiq

echo '{"a":1,"b":2,"c":3}' | xidel -s - -e '{|$json,{"d":4}|}'
{
  "a": 1,
  "b": 2,
  "c": 3,
  "d": 4
}

XQuery 3.1(需要Xidel 0.9.9-beta):

echo '{"a":1,"b":2,"c":3}' | xidel -s - -e 'map:put($json,"d",4)'
{
  "d": 4,
  "a": 1,
  "b": 2,
  "c": 3
}

echo '{"a":1,"b":2,"c":3}' | xidel -s - -e 'map:merge(($json,{"d":4}))'
{
  "a": 1,
  "b": 2,
  "c": 3,
  "d": 4
}

删除属性值对"d":4

JSONiq

echo '{"a":1,"b":2,"c":3,"d":4}' | xidel -s - --xmlns:jnlib="http://jsoniq.org/function-library" -e 'jnlib:remove-keys($json,"d")'
{
  "a": 1,
  "b": 2,
  "c": 3
}

XQuery 3.1(需要Xidel 0.9.9-beta):

echo '{"a":1,"b":2,"c":3,"d":4}' | xidel -s - -e 'map:remove($json,"d")'
{
  "a": 1,
  "b": 2,
  "c": 3
}

答案 5 :(得分:0)

这是一个纯 bash 示例,包括“逗号问题”。

#!/bin/bash
# This bash script just uses the sed command to 
#   replace/insert a new key at/before/after an 
#   existing key in a json file 
# The comma issue:
# - replace: with/without, as previous entry
# - before: always add
# - after: add before, if there was none
SED_CMD="/tmp/sed_cmd.tmp"
JSFILE1="./data1.json"
JSFILE2="./data2.json"
JSFILE3="./data3.json"
SEARCH_KEY="key3"
# create json input file
echo -e '{\n\t"key1": "value1",\n\t"key2": "value2",\n\t"key3": "value3"\n}' > $JSFILE1
echo -e "input:"
cat $JSFILE1
# duplicate twice
cp $JSFILE1 $JSFILE2 && cp $JSFILE1 $JSFILE3
# find the SEARCH_KEY and store the complete line to SEARCH_LINE 
SEARCH_LINE=`cat data.json | grep $SEARCH_KEY`
echo "SEARCH_LINE=>$SEARCH_LINE<"
# replace SEARCH_LINE
IS_COMMA=`echo $SEARCH_LINE | grep ","`
[ -z "$IS_COMMA" ] && \
    echo "s+$SEARCH_LINE+\t\"keyNew\": \"New\"+g" > $SED_CMD || \
    echo "s+$SEARCH_LINE+\t\"keyNew\": \"New\",+g" > $SED_CMD
sed -i -f $SED_CMD $JSFILE1
echo -e "replace:"
cat $JSFILE1
# insert before SEARCH_LINE
echo "s+$SEARCH_LINE+\t\"keyNew\": \"New\",\n$SEARCH_LINE+g" > $SED_CMD
sed -i -f $SED_CMD $JSFILE2
echo -e "before:"
cat $JSFILE2
# insert after SEARCH_LINE
IS_COMMA=`echo $SEARCH_LINE | grep ","`
[ -z "$IS_COMMA" ] && \
    echo "s+$SEARCH_LINE+$SEARCH_LINE,\n\t\"keyNew\": \"New\"+g" > $SED_CMD || \
    echo "s+$SEARCH_LINE+$SEARCH_LINE\n\t\"keyNew\": \"New\",+g" > $SED_CMD
sed -i -f $SED_CMD $JSFILE3
echo -e "after:"
cat $JSFILE3
exit 0