我写了一个脚本将 的输出转换
nmcli --mode multiline dev wifi
为 JSON,但我发现它不一致(当结果有空格时中断),又长又难读。
我想知道是否可以将结果直接通过管道传输到jq
.
输出nmcli
(我的脚本的输入)如下所示:
*:
SSID: VIDEOTRON2255
MODE: Infra
CHAN: 11
RATE: 54 Mbit/s
SIGNAL: 69
BARS: ▂▄▆_
SECURITY: WPA1 WPA2
*: *
SSID: VIDEOTRON2947
MODE: Infra
CHAN: 6
RATE: 54 Mbit/s
SIGNAL: 49
BARS: ▂▄__
SECURITY: WPA1 WPA2
我希望生成这样的东西:
[{
"network": "VIDEOTRON2255",
"mode": "Infra",
"chan": "11",
"rate": "54 Mbit/s",
"signal": "69",
"bars": "▂▄▆_",
"security": "WPA1 WPA2"
},
{
"network": "VIDEOTRON2947",
"mode": "Infra",
"chan": "6",
"rate": "54 Mbit/s",
"signal": "49",
"bars": "▂▄__",
"security": "WPA1 WPA2"
}]
我问了一个相关问题早些时候。这是第一个脚本我写的基于吉尔斯的回答。它适用于某些值,但不适用于带有空格的security
或rate
。
答案1
您链接到的脚本效率极低 - 您正在执行大量无用的预处理...在模式下
使用,因为根据手册,nmcli
--terse
“这种模式是专为计算机(脚本)处理而设计的”,指定所需的字段并将输出通过管道传输到jq -sR
例如
printf '%s' "$(nmcli -f ssid,mode,chan,rate,signal,bars,security -t dev wifi)" | \
jq -sR 'split("\n") | map(split(":")) | map({"network": .[0],
"mode": .[1],
"channel": .[2],
"rate": .[3],
"signal": .[4],
"bars": .[5],
"security": .[6]})'
答案2
这GNU sed
代码不是jq
,(它不是一个复杂的转换),但它似乎工作得足够好,(甚至酒吧出来就OK了):
nmcli --mode multiline dev wifi |
sed '/^*/! {s/^[A-Z]*/\L&/
s/ssid/network/
s/: */": "/
s/$/"/
{/^sec/!s/$/,/}
s/^/\t"/}
1 s/^\*.*/[{/
/^\*/ s/.*/},\n{/
$ {p;s/.*/}]/}'
更容易阅读独立pcsvp.sed
脚本(保存到文件,然后运行chmod +x pcsvp.sed
):
#!/bin/sed -f
# Text lines (the non "*:" lines.)
/^*/! {s/^[A-Z]*/\L&/
s/ssid/network/
s/: */": "/
s/$/"/
{/^sec/!s/$/,/}
s/^/\t"/}
# First JSON line
1 s/^\*.*/[{/
# Middle JSON lines. If a line begins with a '*'...
/^\*/ s/.*/},\n{/
# Last line, close up the JSON.
$ {p;s/.*/}]/}
要运行它,请执行以下操作:
nmcli --mode multiline dev wifi | ./pcsvp.sed
注:由于有对输入文件的疑问,我选择使用nmcli
输入代替。在我所在的位置,这显示了大约 50 个网络,这使得生成的输出太长,无法在此处引用。
如果输入样本拼写错误被更正,./pcsvp.sed input.txt
则输出:
[{
"network": "VIDEOTRON2255",
"mode": "Infra",
"chan": "11",
"rate": "54 Mbit/s",
"signal": "69",
"bars": "▂▄▆_",
"security": "WPA1 WPA2"
},
{
"network": "VIDEOTRON2947",
"mode": "Infra",
"chan": "6",
"rate": "54 Mbit/s",
"signal": "49",
"bars": "▂▄__",
"security": "WEP"
}]
答案3
复杂的jq
解决方案(BARS
删除该行,因为它包含不规则/非 ASCII 字符):
输入文件input.txt
:
*:
SSID: VIDEOTRON2255
MODE: Infra
CHAN: 11
RATE: 54 Mbit/s
SIGNAL: 69
SECURITY: WPA1 WPA2
*: *
SSID: VIDEOTRON2947
MODE: Infra
CHAN: 6
RATE: 54 Mbit/s
SIGNAL: 49
SECURITY: WPA1 WPA2
工作:
jq -sR '[ gsub("[*]: *\n| {2,}";"") | gsub("SSID";"network") | split("\n[*]:[*] +\n";"n")[]
| [ capture("(?<key>[^:\n]+):(?<value>[^:\n]+)";"g") | .key |= (. | ascii_downcase) ]
| from_entries ]' input.txt
输出:
[
{
"network": "VIDEOTRON2255",
"mode": "Infra",
"chan": "11",
"rate": "54 Mbit/s",
"signal": "69",
"security": "WPA1 WPA2"
},
{
"network": "VIDEOTRON2947",
"mode": "Infra",
"chan": "6",
"rate": "54 Mbit/s",
"signal": "49",
"security": "WPA1 WPA2"
}
]
提出/发布的另一个特定输入的附加方法https://pastebin.com/8stHSUeu:
jq -sR '[sub("[*]: *[*]\n";"") | gsub(" {2,}";"") | gsub("SSID";"network")
| split("\n[*]: *\n";"n")[]
| [ capture("(?<key>[^:\n]+):(?<value>[^:\n]+)";"g") | .key |= (. | ascii_downcase) ]
| from_entries]' input.txt
答案4
如果可以的话,请使用能够前后理解 JSON 的工具。我会使用Python:
#! /usr/bin/env python3
import json
import re
import sys
objects = []
obj = {}
for line in sys.stdin:
entry = re.split(':\s*', line.strip(), maxsplit=1) # split on first `:`
if entry[0] == '*':
if obj: # skip a null entry (the first, here)
obj['network'] = obj.pop('ssid') # rename the SSID entry
objects.append(obj)
obj = {} # start a new object for each `*`
continue
obj[entry[0].lower()] = entry[1] # lowercase the key
obj['network'] = obj.pop('ssid') # rename the SSID entry
objects.append(obj)
json.dump(objects, sys.stdout)
让我明白:
[{"mode": "Infra", "chan": "11", "rate": "54 Mbit/s", "signal": "69", "bars": "\u2582\u2584\u2586_", "security": "WPA1 WPA2", "network": "VIDEOTRON2255"}, {"ssid": "VIDEOTRON2947", "mode": "Infra", "chan": "6", "rate": "54 Mbit/s", "signal": "49", "bars": "\u2582\u2584__", "security": "WPA1 WPA2"}]
当打印精美时jq
是:
[
{
"mode": "Infra",
"chan": "11",
"rate": "54 Mbit/s",
"signal": "69",
"bars": "▂▄▆_",
"security": "WPA1 WPA2",
"network": "VIDEOTRON2255"
},
{
"ssid": "VIDEOTRON2947",
"mode": "Infra",
"chan": "6",
"rate": "54 Mbit/s",
"signal": "49",
"bars": "▂▄__",
"security": "WPA1 WPA2"
}
]