我想将命令的输出转换ps
为 JSON,以便将其作为结构化数据进行处理(使用 杰克在这种特殊情况下)。我怎么做?
输出如下所示:
PID TTY TIME CMD
20162 pts/2 00:00:00 ps
28280 pts/2 00:00:02 zsh
标题行始终存在。
答案1
在 JSON 中,有两种明显的方式来表示列式数据输出:作为数组的数组和作为对象的数组。在前一种情况下,您将输入的每一行转换为数组;在后者中,针对一个对象。
ps
下面列出的命令至少适用于 Linux 上的 procps-ng 命令和 的输出ps -l
。
选项#1:数组的数组
使用 Perl
您可以使用 Perl 和 CPAN 模块转换输出JSON::XS。
# ps | perl -MJSON -lane 'my @a = @F; push @data, \@a; END { print encode_json \@data }'
[["PID","TTY","TIME","CMD"],["12921","pts/2","00:00:00","ps"],["12922","pts/2","00:00:00","perl"],["28280","pts/2","00:00:01","zsh"]]
使用jq
或者,您可以使用 jq 本身来执行转换。
# ps | jq -sR '[sub("\n$";"") | splits("\n") | sub("^ +";"") | [splits(" +")]]'
[
[
"PID",
"TTY",
"TIME",
"CMD"
],
[
"16694",
"pts/2",
"00:00:00",
"ps"
],
[
"16695",
"pts/2",
"00:00:00",
"jq"
],
[
"28280",
"pts/2",
"00:00:02",
"zsh"
]
]
选项#2:对象数组
您可以通过从标题行获取键名称,将输入转换为具有有意义命名键的 JSON 对象数组。
这需要更多的努力,尤其是在 jq 中稍微棘手。然而,结果可以说更具人类可读性。
使用 Perl
# ps | perl -MJSON -lane 'if (!@keys) { @keys = @F } else { my %h = map {($keys[$_], $F[$_])} 0..$#keys; push @data, \%h } END { print encode_json \@data }'
[{"TTY":"pts/2","CMD":"ps","TIME":"00:00:00","PID":"11030"},{"CMD":"perl","TIME":"00:00:00","PID":"11031","TTY":"pts/2"},{"TTY":"pts/2","CMD":"zsh","TIME":"00:00:01","PID":"28280"}]
请注意,每个条目的键顺序是任意的。这是 Perl 哈希工作原理的产物。
使用jq
# ps | jq -sR '[sub("\n$";"") | splits("\n") | sub("^ +";"") | [splits(" +")]] | .[0] as $header | .[1:] | [.[] | [. as $x | range($header | length) | {"key": $header[.], "value": $x[.]}] | from_entries]'
[
{
"PID": "19978",
"TTY": "pts/2",
"TIME": "00:00:00",
"CMD": "ps"
},
{
"PID": "19979",
"TTY": "pts/2",
"TIME": "00:00:00",
"CMD": "jq"
},
{
"PID": "28280",
"TTY": "pts/2",
"TIME": "00:00:02",
"CMD": "zsh"
}
]
答案2
我写了一个名为 的命令行工具jc
。它可以将许多命令行工具的输出转换为 JSON,包括ps
.
$ jc ps -ef | jq
[
{
"uid": "root",
"pid": 1,
"ppid": 0,
"c": 0,
"stime": "Sep13",
"tty": null,
"time": "00:00:12",
"cmd": "/usr/lib/systemd/systemd --switched-root --system --deserialize 22"
},
{
"uid": "root",
"pid": 2,
"ppid": 0,
"c": 0,
"stime": "Sep13",
"tty": null,
"time": "00:00:00",
"cmd": "[kthreadd]"
},
...
]
答案3
我建议您作为起点 - 不要使用ps
然后解析它。这是给自己带来痛苦的好方法(比如 - 你想扩展它以包含命令行参数,这些参数是用空格分隔的)。
所以一个简单的就是:
#!/usr/bin/env perl
use strict;
use warnings;
use JSON;
use Proc::ProcessTable;
my $json;
foreach my $proc ( @{ Proc::ProcessTable -> new -> table } ) {
push ( @$json, { %$proc } );
}
print to_json ( $json, { pretty => 1 } );
这将为您提供完整的字段列表ps
,其中有些字段可能是多余的。
如果你想把它做成单衬:
perl -MJSON -MProc::ProcessTable -e 'print to_json ( [ map { %$_ } } @{ Proc::ProcessTable->new->table } ], { pretty => 1 } );'
答案4
我建议使用 -o 选项明确设置您希望 ps 输出的内容。另外,如果您不想在 json 输出中包含标头,请使用 --no-header。