Je veux convertir la sortie de la command ps
en JSON afin de la traiter comme des données structurées (avec jq dans ce cas particulier). Comment je fais ça?
La sortie ressemble à ce qui suit:
PID TTY TIME CMD 20162 pts/2 00:00:00 ps 28280 pts/2 00:00:02 zsh
La ligne d'en-tête est toujours présente.
Il existe deux manières évidentes de représenter la sortie de données en colonnes dans JSON: en tant que tableau de arrays et en tant que tableau d'objects. Dans le premier cas, vous convertissez chaque ligne de l'input en un tableau; dans ce dernier, à un object.
Les commands listées ci-dessous fonctionnent au less avec la sortie de procps-ng sous Linux pour les commands ps
et ps -l
.
Vous pouvez convertir la sortie en utilisant Perl et le module 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"]]
Alternativement, vous pouvez utiliser jq lui-même pour effectuer la conversion.
# 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" ] ]
Vous pouvez convertir l'input en un tableau d'objects JSON avec des keys nommées de manière significative en prenant les noms de key de la ligne d'en-tête.
Cela nécessite un peu plus d'effort et est un peu plus délicat en jq en particulier. Cependant, le résultat est sans doute plus lisible par l'homme.
# 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"}]
Notez que les keys sont dans un ordre arbitraire pour chaque input. C'est un artefact de la façon dont les hachages de Perl fonctionnent.
# ps | jq -sR '[sub("\n$";"") | splits("\n") | sub("^ +";"") | [splits(" +")]] | .[0] as $header | .[1:] | [.[] | [. as $x | range($header | length) | {"key": $header[.], "value": $x[.]}] | from_ensortinges]' [ { "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" } ]
Je suggère explicitement de définir ce que vous voulez que la sortie ps soit avec l'option -o. En outre, utilisez –no-en-tête si vous ne voulez pas l'en-tête dans votre sortie json.
Je suggérerais comme sharepoint départ – ne pas utiliser ps
et ensuite l'parsingr. C'est un bon moyen de vous faire mal (comme par exemple – vous voulez l'étendre pour inclure des arguments de command line, qui sont délimités par des espaces).
Donc, un simple serait:
#!/usr/bin/env perl use ssortingct; 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 } );
Cela vous donnera une list complète des champs ps
, dont certains peuvent être redondants.
Et si vous voulez en faire un seul liner:
perl -MJSON -MProc::ProcessTable -e 'print to_json ( [ map { %$_ } } @{ Proc::ProcessTable->new->table } ], { pretty => 1 } );'