使用命令的输出在bash中创建JSON对象

使用命令的输出在bash中创建JSON对象,json,bash,macos,Json,Bash,Macos,在shell脚本中,我尝试从命令动态获取输出,并将其转换为json对象。谢天谢地,输出被分离成一种格式,这样应该很容易,因为输出实际上是“键”:“值”。这应该很容易,对吧?但我一直在摆弄和阅读这么多的线索,我的头现在正在旋转,我不知道现在该走哪条路 我似乎不知道如何在一个运行在vanilla macOS主机上的bash脚本(它需要一个shell脚本)中实现这一点(没有使用brew或编译添加命令) 我尝试使用“diskutil info/dev/disk2”这样的命令,该命令输出如下数据:

在shell脚本中,我尝试从命令动态获取输出,并将其转换为json对象。谢天谢地,输出被分离成一种格式,这样应该很容易,因为输出实际上是“键”:“值”。这应该很容易,对吧?但我一直在摆弄和阅读这么多的线索,我的头现在正在旋转,我不知道现在该走哪条路

我似乎不知道如何在一个运行在vanilla macOS主机上的bash脚本(它需要一个shell脚本)中实现这一点(没有使用brew或编译添加命令)

我尝试使用“diskutil info/dev/disk2”这样的命令,该命令输出如下数据:

   Device Identifier:         disk2
   Device Node:               /dev/disk2
   Whole:                     Yes
   Part of Whole:             disk2
   Device / Media Name:       DataTraveler G3

   Volume Name:               Not applicable (no file system)
   Mounted:                   Not applicable (no file system)
   File System:               None

   Content (IOContent):       GUID_partition_scheme
   OS Can Be Installed:       No
   Media Type:                Generic
   Protocol:                  USB
   SMART Status:              Not Supported

   Disk Size:                 31.0 GB (30967529472 Bytes) (exactly 60483456 512-Byte-Units)
   Device Block Size:         512 Bytes

   Read-Only Media:           No
   Read-Only Volume:          Not applicable (no file system)

   Device Location:           External
   Removable Media:           Removable
   Media Removal:             Software-Activated

   Virtual:                   No
{   "Device Identifier" : "disk2",
    "Device Node" : "/dev/disk2",
    "Whole" : "Yes",
    "Part of Whole" : "disk2",
    "Device / Media Name" : "DataTraveler G3",
    "Volume Name" : "Not applicable (no file system)",
    "Mounted" : "Not applicable (no file system)",
    "File System" : "None",
    "Content (IOContent)" : "GUID_partition_scheme",
    "OS Can Be Installed" : "No",
    "Media Type" : "Generic",
    "Protocol" : "USB",
    "SMART Status" : "Not Supported",
    "Disk Size" : "31.0 GB (30967529472 Bytes) (exactly 60483456 512-Byte-Units)",
    "Device Block Size" : "512 Bytes",
    "Read-Only Media" : "No",
    "Read-Only Volume" : "Not applicable (no file system)",
    "Device Location" : "External",
    "Removable Media" : "Removable",
    "Media Removal" : "Software-Activated",
    "Virtual" : "No"
}
并获取一个(有效)JSON对象,如下所示:

   Device Identifier:         disk2
   Device Node:               /dev/disk2
   Whole:                     Yes
   Part of Whole:             disk2
   Device / Media Name:       DataTraveler G3

   Volume Name:               Not applicable (no file system)
   Mounted:                   Not applicable (no file system)
   File System:               None

   Content (IOContent):       GUID_partition_scheme
   OS Can Be Installed:       No
   Media Type:                Generic
   Protocol:                  USB
   SMART Status:              Not Supported

   Disk Size:                 31.0 GB (30967529472 Bytes) (exactly 60483456 512-Byte-Units)
   Device Block Size:         512 Bytes

   Read-Only Media:           No
   Read-Only Volume:          Not applicable (no file system)

   Device Location:           External
   Removable Media:           Removable
   Media Removal:             Software-Activated

   Virtual:                   No
{   "Device Identifier" : "disk2",
    "Device Node" : "/dev/disk2",
    "Whole" : "Yes",
    "Part of Whole" : "disk2",
    "Device / Media Name" : "DataTraveler G3",
    "Volume Name" : "Not applicable (no file system)",
    "Mounted" : "Not applicable (no file system)",
    "File System" : "None",
    "Content (IOContent)" : "GUID_partition_scheme",
    "OS Can Be Installed" : "No",
    "Media Type" : "Generic",
    "Protocol" : "USB",
    "SMART Status" : "Not Supported",
    "Disk Size" : "31.0 GB (30967529472 Bytes) (exactly 60483456 512-Byte-Units)",
    "Device Block Size" : "512 Bytes",
    "Read-Only Media" : "No",
    "Read-Only Volume" : "Not applicable (no file system)",
    "Device Location" : "External",
    "Removable Media" : "Removable",
    "Media Removal" : "Software-Activated",
    "Virtual" : "No"
}
现在,是的,我可以使用awk或其他东西手工构建这个,以查找“设备标识符:”并将$0分配给值。但是这个diskutil命令的结果是动态的,并且会根据设备文件中的存储类型而变化(/dev/disk2 vs/dev/disk3 vs/dev/disk4,等等)。那就完了

diskutil命令有一个创建-plist的选项,macOS有一个名为plutil的实用程序,可以将plist转换为json。。。是的,对吗?除了1)plist必须写入文件,因为plutil只读取文件,2)json对象的格式无效。不用谢。那就完了

我可以使用sed抓取冒号前面的字符串,并将它们放入一个键变量中。我可以使用sed来获取冒号后面的字符串,并将它们放在一个变量中作为值。但是我不知道怎么把它们拉成一对。我想知道我是否可以创建一个数组并动态地创建键/值对,一次一个,但我似乎也不明白这一点

也许我累了,或者这是不可能的(或者使用普通命令非常困难),但是我很感激任何人能给我一些指导,帮助我把石头向前移动一点。 谢谢

(旁注:我刚刚开始了解这个macOS主机上的“apropos json”,因此将其作为一个选项进行深入研究……呸,死胡同。)

使用一种提供json库的语言(如Python,包含在股票macOS中)。这里的示例数据并没有做任何简单的字符串操作技术无法处理的事情,但是一旦你有了一个在其名称中包含引号或反斜杠的卷标,那么简单的答案就会严重中断;相比之下,下面的代码将始终发出有效的JSON作为其输出

#!/bin/sh
diskutil info /dev/disk2 | python -c '
import re, sys, json

content_re = re.compile(r"^\s*(\S[^:]+):\s*(\S(?:.*\S)?)\s*$")
content = {}

for line in sys.stdin:
    match = content_re.match(line)
    if match == None:
        continue
    content[match.group(1)] = match.group(2)
json.dump(content, sys.stdout, indent=4)
'
…正确地作为输出发出(给定一个
diskutil
发出您声明的输入):

{
“设备标识符”:“disk2”,
“设备节点”:“/dev/disk2”,
“全部”:“是的”,
“整体的一部分”:“disk2”,
“设备/媒体名称”:“DataTraveler G3”,
“卷名”:“不适用(无文件系统)”,
“已装入”:“不适用(无文件系统)”,
“文件系统”:“无”,
“内容(IOContent)”:“GUID\u分区\u方案”,
“可以安装操作系统”:“否”,
“媒体类型”:“通用”,
“协议”:“USB”,
“智能状态”:“不受支持”,
“磁盘大小”:“31.0 GB(30967529472字节)(正好是60483456 512字节单位)”,
“设备块大小”:“512字节”,
“只读媒体”:“否”,
“只读卷”:“不适用(无文件系统)”,
“设备位置”:“外部”,
“可移动媒体”:“可移动”,
“介质移除”:“软件已激活”,
“虚拟”:“否”
}
#/bin/perl
#./r.pl
如果使用连字符,
plutil
可以从stdin读取并写入stdout。
jq
可以使用下面的Json

diskutil info-plist/dev/disk1 | plutil-convert json-r-o--

为什么它“需要是bash脚本”?普通的MacOS主机具有现成的Python。事实上,即使您要加倍使用needs-to-be-a-bash-script,最好的答案将是启动Python的bash脚本,因为Python有JSON库,而bash没有。当卷名中有引号并且需要从包含
更改为
\”
时会发生什么?或者一个反斜杠需要加倍才能成为有效的JSON,或者一个制表符需要更改为
\t
,或者一个不可打印字符需要更改为
\u###
转义?(另外,
/r.pl
/r.pl info/dev/disk2 Regex相同,当值为单个字符时,它们将不匹配。显然,是的。在编写它时,我认为这比作为数据的一部分在行尾捕获空格要好。也就是说,它已被修改以解决此问题。是不是要做的事更简单:…:\s*(*?)\s*$
?这当然也是一个合理的方法。