我有一个 JSON 主配置文件,其值可能会被特定帐户的配置文件(也是 JSON 格式)覆盖。主文件具有以下结构:
{
"section1Configs": {
"setting01": true,
"setting02": true,
"setting03": false
},
section2Configs: {
"setting01": true,
"setting02": true,
"setting03": false
},
section3Configs: {
"setting01": true,
"setting02": true,
"setting03": false
},
section4Configs: {
"setting01": true,
"setting02": true,
"setting03": false
}
}
特定帐户的配置文件可能如下所示:
{
"section1Configs": {
"setting01": true,
"setting02": true,
"setting03": true
},
section2Configs: {
"setting01": false,
"setting02": true,
"setting03": false
},
section3Configs: {
"setting01": true,
"setting02": false,
"setting03": false
},
section4Configs: {
"setting01": true,
"setting02": true,
"setting03": false
}
}
请注意,除了某些值(section01Config.setting03、section02Config.setting01 和section03Config.setting02)不同之外,它们是相同的。另请注意,两个文件中的整个section4Configs 块是相同的。
不需要相同的文件,因为应用程序会加载两者并用帐户配置中不同的文件覆盖主文件。
我想做的是有一个脚本,它可以迭代此类帐户文件的目录,并删除每个文件中与主文件具有相同键和值的条目。从这个例子中我最终会得到一个像这样的文件:
{
section1Configs: {
setting03: true
},
section2Configs: {
setting01: false
},
section3Configs: {
setting02: false
}
}
有超过 200 个帐户配置文件,手动执行此操作将花费一生的时间。任何帮助是极大的赞赏!
- - - 编辑 - - - -
我试图让问题变得简单,但我认为缺少细节会对答案产生影响。
帐户和配置 JSON 文件由部分及其相应的设置组成。这意味着 JSON 比上面提到的更深一层:
{
"section1Configs": {
"level1Settings": {
"section01Lev01_01": true,
"section01Lev01_012": true,
"section01Lev01_02": true
}
}
}
谢谢!
答案1
所以我将你的底部内容复制到两个文件中。
文件一:
{
"section1Configs": {
"level1Settings": {
"section01Lev01_01": true,
"section01Lev01_012": true,
"section01Lev01_02": true
}
}
}
还有文件2...
{
"section1Configs": {
"level1Settings": {
"section01Lev01_01": true,
"section01Lev01_012": false,
"section01Lev01_02": true
}
}
}
它们的区别仅在于Level01_012
线。
然后我做了:
grep -Ev '[{}]|^$' file1 | grep -Fxvf- file2
{
"section1Configs": {
"level1Settings": {
"section01Lev01_012": false,
}
}
}
该命令细分如下:
grep -Ev '[{}]|^$' file1
- 在这里我们要求
grep
打印每一行file1
它既不匹配{
字符也不}
匹配字符,但它必须至少匹配一特点。 它的输出看起来像:
"section01Lev01_01": true, "section01Lev01_012": true, "section01Lev01_02": true
- 在这里我们要求
grep -Fxvf- file2
- 这是由这一秒读取的,它将其标准输入模式ile
grep
解释为固定字符串模式整行匹配,它应该 --
-f
-F
-x
v
不是打印输出。因此,这一秒grep
打印 file2 中与 file1 中的真/假行不完全匹配的每一行。
- 这是由这一秒读取的,它将其标准输入模式ile
现在,如果您grep
不理解-
stdin,我们有几个选择:
grep -Ev '[{}]|^$' file1 | grep -Fxvf /dev/fd/0 file2
...适用于大多数系统。一个类似的选项是使用/dev/stdin
,它也很可能有效,如果效果稍差一点的话。
还有一个特定于 shell 的实现,称为流程替代其工作方式几乎完全相同......
grep -Fxvf <(grep -Ev '[{}]|^$' file1) file2
...这可能适合你,也可能不适合你,具体取决于你的 shell。
另一种可能性是...
grep -Fxv "$(grep -Ev '[{}]|^$' file1)" file2
...这可能适合你,也可能不适合你,具体取决于命令替换的输出有多大grep
。
尝试一些,也许您会找到适合您的。
答案2
使用专门用于 json 的工具可能会更好,例如杰克或者杰森?但如果你愿意的话可以用and
来完成paste
sed
paste config master | sed '/[{}]/! {/\(.\+\)\t\1/d;};s/\t.*//'
或者awk
awk '{getline a < "master"} /[{}]/ || $0 != a' config
对于配置文件中的每一行,从主文件中获取相应的(按数字)行到变量中a
,如果行与主文件中的行相同{
或}
不同,则打印它。
结果:
{
"section1Configs": {
"setting03": true
},
section2Configs: {
"setting01": false,
},
section3Configs: {
"setting02": false,
},
section4Configs: {
}
}
答案3
正如本页其他地方所指出的,解决该问题的一种强大而有效的方法是使用 JSON 感知工具,例如杰克。下面提供了原始问题的解决方案;它可以很容易地适应解决变体。
(1) 将以下内容放入文件中,例如 minusConfig.jq:
def minus(o1;o2):
o1 | with_entries( select(o2[.key] != .value) );
def minusConfig(o1;o2):
reduce (o1|keys)[] as $key ({};
minus( o1[$key] ; o2[$key]) as $v
| if $v == {} then . else . + {($key): $v} end );
minusConfig($user; $master)
(2) 假设master和user配置文件分别为master.json和user.json,
$ jq -n --arg master master.json --arg user user.json -f minusConfig.jq
产生:
{
"section1Configs": {
"setting03": true
},
"section2Configs": {
"setting01": false
},
"section3Configs": {
"setting02": false
}
}