옵션 #1: 배열의 배열

옵션 #1: 배열의 배열

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]"
  },
  ...
]

https://github.com/kellyjonbrazil/jc

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

관련 정보