使用 jq + bash 将 json 转换为 ini 文件
Transform json to ini files using jq + bash
我正在尝试将 json(对象数组)转换为 ini 文件:
[
{
"connection": {
"id": "br0",
"uuid": "ab1dd903-4786-4c7e-a4b4-3339b144d6c7",
"stable-id": "",
"type": "bridge",
"interface-name": "br0",
"autoconnect": "no",
"autoconnect-priority": "0",
"autoconnect-retries": "-1",
"auth-retries": "-1",
"timestamp": "44444",
"read-only": "no",
"permissions": "",
"zone": "WAN",
"master": "",
"slave-type": "",
"autoconnect-slaves": "1",
"secondaries": "",
"gateway-ping-timeout": "0",
"metered": "unknown",
"lldp": "default"
},
"ipv4": {
"method": "manual",
"dns": "192.168.1.1,192.168.2.1",
"dns-search": "",
"dns-options": " ",
"dns-priority": "0",
"addresses": "192.168.1.3/24",
"gateway": "",
"routes": "192.168.10.0/24 192.168.1.1",
"route-metric": "-1",
"route-table": "0",
"ignore-auto-routes": "no",
"ignore-auto-dns": "no",
"dhcp-client-id": "",
"dhcp-timeout": "0",
"dhcp-send-hostname": "yes",
"dhcp-hostname": "",
"dhcp-fqdn": "",
"never-default": "no",
"may-fail": "yes",
"dad-timeout": "-1"
}
},
{
"connection": {
...
},
}
]
或
{
"connection": {
...
},
}
我尝试做的是:
1.将 json 转换为字符串
data=$(jq -r 'def keyValue: to_entries[] | "[\(.key)]\n\(.value | to_entries|map("\(.key)=\(.value)" ) | join("\n") )\n"; if type == "array" then keys[] as $k | "\(.[$k] | .connection.id)=\(.[$k] | keyValue)" elif type == "object" then "\(.connection.id)=\(. | keyValue)" else keys end' /tmp/json)
提供:
br1=[connection]\nid=br1\nuuid=ab1dd903-4786-4c7e-a4b4-3339b144d6c7\nstable-id=\ntype=fff\ninterface-name=br0\nautoconnect=no\nautoconnect-priority=0\nautoconnect-retries=-1\nauth-retries=-1\ntimestamp=1525494904\nread-only=no\npermissions=\nzone=WAN\nmaster=\nslave-type=\nautoconnect-slaves=1\nsecondaries=\ngateway-ping-timeout=0\nmetered=unknown\nlldp=default\n
br1=[802-3-ethernet]\nport=\nspeed=0\nduplex=\nauto-negotiate=no\nmac-address=\ncloned-mac-address=\ngenerate-mac-address-mask=\nmac-address-blacklist=\nmtu=1500\ns390-subchannels=\ns390-nettype=\ns390-options=\nwake-on-lan=default\nwake-on-lan-password=\n....
2。遍历 bash
中的字符串
while IFS="=" read -r key value; do [ "$oldkey" = "$key" ] && echo -en "$value" >> "/tmp/ini/$key" || echo -en "$value" > "/tmp/ini/$key" ; oldkey="$key"; done <<< "$data"
给出:
[connection]
id=br1
uuid=ab1dd903-4786-4c7e-a4b4-3339b144d6c7
stable-id=
type=fff
interface-name=br0
autoconnect=no
autoconnect-priority=0
autoconnect-retries=-1
auth-retries=-1
timestamp=1525494904
read-only=no
permissions=
zone=WAN
master=
slave-type=
autoconnect-slaves=1
secondaries=
gateway-ping-timeout=0
metered=unknown
lldp=default
[ipv4]
method=manual
dns=192.168.1.1,192.168.2.1
dns-search=
dns-options=
dns-priority=0
addresses=192.168.1.3/24
gateway=
routes=192.168.10.0/24 192.168.1.1
route-metric=-1
route-table=0
ignore-auto-routes=no
ignore-auto-dns=no
dhcp-client-id=
dhcp-timeout=0
dhcp-send-hostname=yes
dhcp-hostname=
dhcp-fqdn=
never-default=no
may-fail=yes
dad-timeout=-1
我快到了!但是有没有可能做到更多 "elegantly" 和更高效的方式,避免管道、外部调用等
注:而且,大部分应该用jq+bash,因为其他处理工具如sed,awk比我做的慢,但是我不完全拒绝他们 =)
P.S. - 此转换的主要目的是快速 "bulk operation" 写入 ini 文件
要将所示的数组转换为“.ini”格式,只需使用此 jq 程序即可完成:
def kv: to_entries[] | "\(.key)=\(.value)";
.[]
| to_entries[]
| "[\(.key)]", (.value|kv)
将其放入文件中,例如 program.jq,然后假设问题中显示的 JSON(减去“...”部分)在 input.json 中,以下调用:
jq -rf program.jq input.json
生成相应的“.ini”文件。
如果你想保证程序也能处理没有封闭数组的情况,你可以修改上面主程序中的第一行来测试输入是否是一个数组,这样你就可以了:
if type == "array" then .[] else . end
| to_entries[]
| "[\(.key)]", (.value|kv)
如果最终目标是生成多个 .ini 文件,那么我们可以重用 def kv
,如其他答案中所定义:
def kv: to_entries[] | "\(.key)=\(.value)";
驱动程序现在是:
.[]
| [to_entries[] | "[\(.key)]", (.value|kv)]
| join("\n")
运行 jq 然后用这个程序为数组中的每一项生成一个 JSON 字符串。使用该示例,第一个这样的字符串将是:
"[connection]\nid=br0\nuuid=ab1dd903-4786-4c7e-a4b4-3339b144d6c7\nstable-id=\ntype=bridge\ninterface-name=br0\nautoconnect=no\nautoconnect-priority=0\nautoconnect-retries=-1\nauth-retries=-1\ntimestamp=44444\nread-only=no\npermissions=\nzone=WAN\nmaster=\nslave-type=\nautoconnect-slaves=1\nsecondaries=\ngateway-ping-timeout=0\nmetered=unknown\nlldp=default\n[ipv4]\nmethod=manual\ndns=192.168.1.1,192.168.2.1\ndns-search=\ndns-options= \ndns-priority=0\naddresses=192.168.1.3/24\ngateway=\nroutes=192.168.10.0/24 192.168.1.1\nroute-metric=-1\nroute-table=0\nignore-auto-routes=no\nignore-auto-dns=no\ndhcp-client-id=\ndhcp-timeout=0\ndhcp-send-hostname=yes\ndhcp-hostname=\ndhcp-fqdn=\nnever-default=no\nmay-fail=yes\ndad-timeout=-1"
然后您可以遍历这些以换行符分隔的字符串。
我正在尝试将 json(对象数组)转换为 ini 文件:
[
{
"connection": {
"id": "br0",
"uuid": "ab1dd903-4786-4c7e-a4b4-3339b144d6c7",
"stable-id": "",
"type": "bridge",
"interface-name": "br0",
"autoconnect": "no",
"autoconnect-priority": "0",
"autoconnect-retries": "-1",
"auth-retries": "-1",
"timestamp": "44444",
"read-only": "no",
"permissions": "",
"zone": "WAN",
"master": "",
"slave-type": "",
"autoconnect-slaves": "1",
"secondaries": "",
"gateway-ping-timeout": "0",
"metered": "unknown",
"lldp": "default"
},
"ipv4": {
"method": "manual",
"dns": "192.168.1.1,192.168.2.1",
"dns-search": "",
"dns-options": " ",
"dns-priority": "0",
"addresses": "192.168.1.3/24",
"gateway": "",
"routes": "192.168.10.0/24 192.168.1.1",
"route-metric": "-1",
"route-table": "0",
"ignore-auto-routes": "no",
"ignore-auto-dns": "no",
"dhcp-client-id": "",
"dhcp-timeout": "0",
"dhcp-send-hostname": "yes",
"dhcp-hostname": "",
"dhcp-fqdn": "",
"never-default": "no",
"may-fail": "yes",
"dad-timeout": "-1"
}
},
{
"connection": {
...
},
}
]
或
{
"connection": {
...
},
}
我尝试做的是:
1.将 json 转换为字符串
data=$(jq -r 'def keyValue: to_entries[] | "[\(.key)]\n\(.value | to_entries|map("\(.key)=\(.value)" ) | join("\n") )\n"; if type == "array" then keys[] as $k | "\(.[$k] | .connection.id)=\(.[$k] | keyValue)" elif type == "object" then "\(.connection.id)=\(. | keyValue)" else keys end' /tmp/json)
提供:
br1=[connection]\nid=br1\nuuid=ab1dd903-4786-4c7e-a4b4-3339b144d6c7\nstable-id=\ntype=fff\ninterface-name=br0\nautoconnect=no\nautoconnect-priority=0\nautoconnect-retries=-1\nauth-retries=-1\ntimestamp=1525494904\nread-only=no\npermissions=\nzone=WAN\nmaster=\nslave-type=\nautoconnect-slaves=1\nsecondaries=\ngateway-ping-timeout=0\nmetered=unknown\nlldp=default\n
br1=[802-3-ethernet]\nport=\nspeed=0\nduplex=\nauto-negotiate=no\nmac-address=\ncloned-mac-address=\ngenerate-mac-address-mask=\nmac-address-blacklist=\nmtu=1500\ns390-subchannels=\ns390-nettype=\ns390-options=\nwake-on-lan=default\nwake-on-lan-password=\n....
2。遍历 bash
中的字符串while IFS="=" read -r key value; do [ "$oldkey" = "$key" ] && echo -en "$value" >> "/tmp/ini/$key" || echo -en "$value" > "/tmp/ini/$key" ; oldkey="$key"; done <<< "$data"
给出:
[connection]
id=br1
uuid=ab1dd903-4786-4c7e-a4b4-3339b144d6c7
stable-id=
type=fff
interface-name=br0
autoconnect=no
autoconnect-priority=0
autoconnect-retries=-1
auth-retries=-1
timestamp=1525494904
read-only=no
permissions=
zone=WAN
master=
slave-type=
autoconnect-slaves=1
secondaries=
gateway-ping-timeout=0
metered=unknown
lldp=default
[ipv4]
method=manual
dns=192.168.1.1,192.168.2.1
dns-search=
dns-options=
dns-priority=0
addresses=192.168.1.3/24
gateway=
routes=192.168.10.0/24 192.168.1.1
route-metric=-1
route-table=0
ignore-auto-routes=no
ignore-auto-dns=no
dhcp-client-id=
dhcp-timeout=0
dhcp-send-hostname=yes
dhcp-hostname=
dhcp-fqdn=
never-default=no
may-fail=yes
dad-timeout=-1
我快到了!但是有没有可能做到更多 "elegantly" 和更高效的方式,避免管道、外部调用等
注:而且,大部分应该用jq+bash,因为其他处理工具如sed,awk比我做的慢,但是我不完全拒绝他们 =)
P.S. - 此转换的主要目的是快速 "bulk operation" 写入 ini 文件
要将所示的数组转换为“.ini”格式,只需使用此 jq 程序即可完成:
def kv: to_entries[] | "\(.key)=\(.value)";
.[]
| to_entries[]
| "[\(.key)]", (.value|kv)
将其放入文件中,例如 program.jq,然后假设问题中显示的 JSON(减去“...”部分)在 input.json 中,以下调用:
jq -rf program.jq input.json
生成相应的“.ini”文件。
如果你想保证程序也能处理没有封闭数组的情况,你可以修改上面主程序中的第一行来测试输入是否是一个数组,这样你就可以了:
if type == "array" then .[] else . end
| to_entries[]
| "[\(.key)]", (.value|kv)
如果最终目标是生成多个 .ini 文件,那么我们可以重用 def kv
,如其他答案中所定义:
def kv: to_entries[] | "\(.key)=\(.value)";
驱动程序现在是:
.[]
| [to_entries[] | "[\(.key)]", (.value|kv)]
| join("\n")
运行 jq 然后用这个程序为数组中的每一项生成一个 JSON 字符串。使用该示例,第一个这样的字符串将是:
"[connection]\nid=br0\nuuid=ab1dd903-4786-4c7e-a4b4-3339b144d6c7\nstable-id=\ntype=bridge\ninterface-name=br0\nautoconnect=no\nautoconnect-priority=0\nautoconnect-retries=-1\nauth-retries=-1\ntimestamp=44444\nread-only=no\npermissions=\nzone=WAN\nmaster=\nslave-type=\nautoconnect-slaves=1\nsecondaries=\ngateway-ping-timeout=0\nmetered=unknown\nlldp=default\n[ipv4]\nmethod=manual\ndns=192.168.1.1,192.168.2.1\ndns-search=\ndns-options= \ndns-priority=0\naddresses=192.168.1.3/24\ngateway=\nroutes=192.168.10.0/24 192.168.1.1\nroute-metric=-1\nroute-table=0\nignore-auto-routes=no\nignore-auto-dns=no\ndhcp-client-id=\ndhcp-timeout=0\ndhcp-send-hostname=yes\ndhcp-hostname=\ndhcp-fqdn=\nnever-default=no\nmay-fail=yes\ndad-timeout=-1"
然后您可以遍历这些以换行符分隔的字符串。