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과 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를 사용하세요.