我正在使用jq尝试将bash命令输出转换为json。但是,转换使我失败了。
使用此行:
hostname && getent passwd | egrep -v '/s?bin/(nologin|shutdown|sync|halt)' | cut -d: -f1 | sudo xargs -I % sh -c 'echo %; chage -l %; echo' | jq --raw-input . | jq --slurp .
类似这样的事情: JSON
不使用jq的上述命令的输出结果为: Command Output
有人尝试过将bash输出正确转换为json吗?谢谢
答案 0 :(得分:1)
我正在使用jq ...
我意识到jq
在这里很受欢迎,但是我建议为此任务推荐Xidel。
尽管Xidel主要是HTML / XML / JSON解析器(使用CSS,XPath,XQuery,JSONiq和模式模板),但Xidel也可以处理基本文本。
您说您想拥有一个像这样的json:
{
"hostname": "example",
"users": [
{
"username": "example1",
"details": {
"LastPasswordChange": "Nov 12, 2018",
"PasswordExpires": "never",
"PasswordInactive": "never",
"AccountExpires": "never",
"MinDaysBetweenPasswordChange": "0",
"MaxDaysBetweenPasswordChange": "99999",
"NumOfDaysOfWarningBeforePasswordExpires": "7"
}
},
{
"username": "example2",
"details": {
"LastPasswordChange": "Nov 13, 2018",
"PasswordExpires": "never",
"PasswordInactive": "never",
"AccountExpires": "never",
"MinDaysBetweenPasswordChange": "0",
"MaxDaysBetweenPasswordChange": "99999",
"NumOfDaysOfWarningBeforePasswordExpires": "7"
}
}
]
}
这意味着users
数组需要为每个用户分别填充对象(从此chage
程序的输出创建)。这就是为什么我会选择另一种方法。
假设getent passwd | egrep -v '/s?bin/(nologin|shutdown|sync|halt)' | cut -d: -f1
返回:
root
user1
user2
这是我们要传递给Xidel的代码,以首先创建一个基本的json:
getent passwd | egrep -v '/s?bin/(nologin|shutdown|sync|halt)' | cut -d: -f1 | xidel -s - --xquery '
{
"hostname":"'$(hostname)'",
"users":x:lines($raw) ! {
"username":.
}
}
'
hostname &&
,因为您只需从Xidel内部调用即可(这也使查询更加容易)。x:lines($raw)
,您可以根据Xidel的输入(在本例中为stdin)创建每个新行的序列。可以使用的替代功能为tokenize($raw,"\n")
。查询输出:
{
"hostname": "user",
"users": [
{
"username": "root"
},
{
"username": "user1"
},
{
"username": "user2"
}
]
}
接下来,我们将在Xidel中调用chage
以创建details
对象:
getent passwd | egrep -v '/s?bin/(nologin|shutdown|sync|halt)' | cut -d: -f1 | xidel -s - --xquery '
{
"hostname":"'$(hostname)'",
"users":x:lines($raw) ! {
"username":.,
"details":{|
for $x in x:lines(
system(x"chage -l {.}")
)
let $a:=tokenize(
$x,
":"
)
return {
normalize-space($a[1]):normalize-space($a[2])
}
|}
}
}
'
system(x"chage -l {.}")
返回chage -l root
,chage -l user1
和chage -l user2
的输出。x:lines()
周围,您会再次创建每个新行的序列。 user2
输出的第一行,例如:Last password change : Oct 23, 2018
$a
,该变量包含该项目的序列(分为两部分),以:
作为分隔符。 $a
因此,对于第一项:Last password change # white-space up untill this point!
Oct 23, 2018
{
"Last password change": "Oct 23, 2018"
}
查询输出:
{
"hostname": "user",
"users": [
{
"username": "root",
"details": {
"Last password change": "never",
"Password expires": "never",
"Password inactive": "never",
"Account expires": "never",
"Minimum number of days between password change": "0",
"Maximum number of days between password change": "99999",
"Number of days of warning before password expires": "7"
}
},
{
"username": "user1",
"details": {
"Last password change": "never",
"Password expires": "never",
"Password inactive": "never",
"Account expires": "never",
"Minimum number of days between password change": "0",
"Maximum number of days between password change": "99999",
"Number of days of warning before password expires": "7"
}
},
{
"username": "user2",
"details": {
"Last password change": "Oct 23, 2018",
"Password expires": "never",
"Password inactive": "never",
"Account expires": "never",
"Minimum number of days between password change": "0",
"Maximum number of days between password change": "99999",
"Number of days of warning before password expires": "7"
}
}
]
}
您可以再走一步:
getent passwd | egrep -v '/s?bin/(nologin|shutdown|sync|halt)' | cut -d: -f1 | xidel -s - --xquery '
{
"hostname":"'$(hostname)'",
"users":x:lines($raw) ! {
"username":.,
"details":{|
for $x in x:lines(
system(x"chage -l {.}")
)
let $a:=tokenize(
$x,
":"
)
return {
string-join(
for $x in tokenize(
normalize-space($a[1]),
" "
)
return
upper-case(
substring(
$x,
1,
1
)
)||substring(
$x,
2
)
):normalize-space($a[2]) ! (
if (. castable as decimal) then
number(.)
else
.
)
}
|}
}
}
'
Last password change
string-join(for $x in tokenize(normalize-space($a[1])," ") return upper-case(substring($x,1,1))||substring($x,2))
...它返回:LastPasswordChange
。
"99999"
(字符串)
normalize-space($a[2]) ! (if (. castable as decimal) then number(.) else .)
...它返回:99999
作为xs:十进制原子类型。
查询输出:
{
"hostname": "user",
"users": [
{
"username": "root",
"details": {
"LastPasswordChange": "never",
"PasswordExpires": "never",
"PasswordInactive": "never",
"AccountExpires": "never",
"MinimumNumberOfDaysBetweenPasswordChange": 0,
"MaximumNumberOfDaysBetweenPasswordChange": 99999,
"NumberOfDaysOfWarningBeforePasswordExpires": 7
}
},
{
"username": "user1",
"details": {
"LastPasswordChange": "never",
"PasswordExpires": "never",
"PasswordInactive": "never",
"AccountExpires": "never",
"MinimumNumberOfDaysBetweenPasswordChange": 0,
"MaximumNumberOfDaysBetweenPasswordChange": 99999,
"NumberOfDaysOfWarningBeforePasswordExpires": 7
}
},
{
"username": "user2",
"details": {
"LastPasswordChange": "Oct 23, 2018",
"PasswordExpires": "never",
"PasswordInactive": "never",
"AccountExpires": "never",
"MinimumNumberOfDaysBetweenPasswordChange": 0,
"MaximumNumberOfDaysBetweenPasswordChange": 99999,
"NumberOfDaysOfWarningBeforePasswordExpires": 7
}
}
]
}
“美化”查询更容易阅读,但是如果您希望使用“美化”版本:
getent passwd | egrep -v '/s?bin/(nologin|shutdown|sync|halt)' | cut -d: -f1 | xidel -s - --xquery '{"hostname":"'$(hostname)'","users":x:lines($raw) ! {"username":.,"details":{|for $x in x:lines(system(x"chage -l {.}")) let $a:=tokenize($x,":") return {string-join(for $x in tokenize(normalize-space($a[1])," ") return upper-case(substring($x,1,1))||substring($x,2)):normalize-space($a[2]) ! (if (. castable as decimal) then number(.) else .)}|}}}'
答案 1 :(得分:0)
这是一个perl脚本,以JSON格式显示/etc/passwd
的主机名和内容(在我熟悉的任何操作系统上,输出看起来都不是您的示例,顺便说一句。)
请注意,在谈论JSON对象的键时,“第一个元素”当然没有任何意义;他们是无序的。如果您依赖于某个特定键位于对象中的特定位置,那么您做错了。
#!/usr/bin/env perl
use warnings;
use strict;
use Sys::Hostname;
use User::pwent;
# Might have to install through your OS's package manager or
# with your favorite CPAN client
use JSON;
my %pwdb = ( hostname => hostname(), users => [] );
while (my $pw = getpwent) {
# Ignore users with certain shells
next if
defined $pw->shell && $pw->shell =~ m!s?bin/(nologin|shutdown|sync|halt)!;
push @{$pwdb{"users"}}, {
username => $pw->name,
details => {
passwd => $pw->passwd,
uid => $pw->uid,
gid => $pw->gid,
change => $pw->change,
age => $pw->age,
quota => $pw->quota,
comment => $pw->comment,
class => $pw->class,
gecos => $pw->gecos,
dir => $pw->dir,
shell => $pw->shell,
expire => $pw->expire
}
};
}
my $pp = JSON->new->ascii->pretty;
print $pp->encode(\%pwdb);