
ps
構造化データで処理できるように、コマンドの出力をJSONに変換したい(次を使用)。ジャックこの特別な場合)。どうすればいいですか?
出力は次のとおりです。
PID TTY TIME CMD
20162 pts/2 00:00:00 ps
28280 pts/2 00:00:02 zsh
ヘッダー行は常に存在します。
答え1
JSONには、列形式のデータ出力を表す2つの明確な方法があります。配列を配列に、配列をオブジェクトとして表現するものです。前者の場合、入力の各行をオブジェクトの配列に変換します。
ps
以下のコマンドは、少なくともLinux上のprocps-ngコマンドの出力に適用されますps -l
。
オプション#1:配列の配列
パールを使う
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では少し難しいです。しかし、結果は間違いなく人が読みやすくなります。
パールを使う
# 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
。 .NETを含む多くのコマンドラインツールの出力を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
psが出力する内容を明示的に設定するには、-oオプションを使用することをお勧めします。また、json出力にヘッダーを含めたくない場合は、--no-headerを使用してください。