getent passwd以正确格式作为json输出

getent passwd以正确格式作为json输出,json,linux,bash,shell,format,Json,Linux,Bash,Shell,Format,我使用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是为了尝试将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的根元素
  • 用户名必须是第一个元素
  • getent passwd输出必须是username的子元素
大概是这样的:

在不使用jq的情况下输出上述命令会导致:


有人试过将bash输出正确地转换为json吗?谢谢

这里有一个perl脚本,它以JSON格式显示
/etc/passwd
的主机名和内容(顺便说一句,在我熟悉的任何操作系统上,输出看起来都不像您的示例。)

请注意,当谈论JSON对象的键时,“第一个元素”当然毫无意义;它们是无序的。如果您依赖于对象中特定位置的特定键,那么您就做错了

#/usr/bin/env perl
使用警告;
严格使用;
使用Sys::Hostname;
使用User::pwent;
#可能必须通过操作系统的软件包管理器或
#和你最喜欢的CPAN客户端
使用JSON;
我的%pwdb=(主机名=>hostname(),用户=>[]);
while(my$pw=getpwent){
#忽略具有特定shell的用户
下一个如果
定义了$pw->shell&&$pw->shell=~m!s?bin/(nologin | shutdown | sync | halt)!;
推送{$pwdb{“用户”}{
用户名=>$pw->name,
详细信息=>{
passwd=>$pw->passwd,
uid=>$pw->uid,
gid=>$pw->gid,
更改=>$pw->更改,
年龄=>$pw->年龄,
配额=>$pw->配额,
comment=>$pw->comment,
class=>$pw->class,
gecos=>$pw->gecos,
dir=>$pw->dir,
外壳=>$pw->外壳,
expire=>$pw->expire
}
};
}
我的$pp=JSON->new->ascii->pretty;
打印$pp->编码(\%pwdb);
我在用jq

我意识到
jq
在这里很受欢迎,但我将推荐这项任务。
虽然Xidel主要是一个HTML/XML/JSON解析器(使用CSS、XPath、XQuery、JSONiq和模式模板),但它也可以处理基本文本

你说你想要一个像这样的json:

{
“主机名”:“示例”,
“用户”:[
{
“用户名”:“示例1”,
“详情”:{
“LastPasswordChange”:“2018年11月12日”,
“PasswordExpires”:“从不”,
“PasswordInactive”:“从不”,
“AccountExpires”:“从不”,
“MindaysBetween密码更改”:“0”,
“MaxDaysBetween密码更改”:“99999”,
密码过期前的警告天数:“7”
}
},
{
“用户名”:“示例2”,
“详情”:{
“LastPasswordChange”:“2018年11月13日”,
“PasswordExpires”:“从不”,
“PasswordInactive”:“从不”,
“AccountExpires”:“从不”,
“MindaysBetween密码更改”:“0”,
“MaxDaysBetween密码更改”:“99999”,
密码过期前的警告天数:“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)创建每一行的序列。另一个可使用的函数是
    标记化($raw,“\n”)
查询输出:

{
  "hostname": "user",
  "users": [
    {
      "username": "root"
    },
    {
      "username": "user1"
    },
    {
      "username": "user2"
    }
  ]
}
{
  "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"
      }
    }
  ]
}
{
  "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
      }
    }
  ]
}
接下来,我们将从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
    输出的第一行,例如:
  • 对于此序列(或行)中的每个项目,将创建变量
    $a
    ,该变量将此项目的序列一分为二,并以
    作为分隔符<代码>$a因此,对于第一项:
  • 最后创建属性值对,并规范化空白:
查询输出:

{
  "hostname": "user",
  "users": [
    {
      "username": "root"
    },
    {
      "username": "user1"
    },
    {
      "username": "user2"
    }
  ]
}
{
  "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"
      }
    }
  ]
}
{
  "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
              .
          )
        }
      |}
    }
  }
'
  • 不是上次更改密码,而是
…它返回:
LastPasswordChange

  • 而不是
    “99999”
    (一个字符串),使用
…它以xs:decimal原子类型返回:
99999

查询输出:

{
  "hostname": "user",
  "users": [
    {
      "username": "root"
    },
    {
      "username": "user1"
    },
    {
      "username": "user2"
    }
  ]
}
{
  "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"
      }
    }
  ]
}
{
  "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
      }
    }
  ]
}
“美化”查询更容易阅读,但如果您更喜欢“精简”版本:


好的,我知道你想要的输出来自哪里;此更改程序,而不是passwd数据库。在你的问题中,你真的应该更清楚这一点。我会在有机会的时候更新我的答案。谢谢你的回答。我在某个地方找到了命令,但还不太擅长bash。这就是为什么我不能说得更清楚。你能给我们看一下主机名和getent passwd | egrep-v'/s?bin/(nologin | shutdown | sync | halt)| cut-d:-f1 | sudo xargs-i%sh-c'echo%;查格-1%;回显“(密码被屏蔽)?当然。输出现在添加到上面。哇。T