Makefile: Убейте процесс, если он работает

Есть два очевидных способа представления колоночных данных в JSON: как массив массивов и как массив объектов. В первом случае вы преобразуете каждую строку входных данных в массив, во втором - в объект.

Перечисленные ниже команды работают, по крайней мере, с выводом procps-ng в Linux для команд ps и 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"
  }
]

6
10.06.2018, 03:39
3 ответа

Necesita un ||truepara asegurarse de que el primer comando siempre devuelva el éxito.

Puede evitar la necesidad de pgrepdesechando stderr; p.ej.

test: client server
  killall myserver 2>/dev/null || true
  myserver --background
  myclient --server 127.0.0.1
7
27.01.2020, 20:20

No combine killallcon pgrep. No usan las mismas reglas de coincidencia, por lo que lo que muestra pgreppuede no ser lo que mata killall. Use pkill, que es exactamente lo mismo que pgrepexcepto que elimina los procesos coincidentes en lugar de mostrar sus PID. Tenga en cuenta que si llama tanto a pgrepcomo a pkill, hay una condición de carrera :en el momento en que se ejecuta pkill, algunos procesos mostrados por pgreppueden haber terminado y algunos procesos nuevos pueden haber comenzado. A menos que le interesen los ID de proceso, no tiene sentido llamar a pgrep; simplemente puede llamar al pkilldirectamente.

pkilldevuelve el estado 1 si no encuentra ningún proceso para matar. Agregue -al comienzo del comando, para indicarle a make que ignore este error, o cambie el comando a pkill myserver || true, que hace exactamente lo mismo que pkill myserverpero siempre devuelve un estado de éxito.

test: client server
    pkill myserver || true
    /build/bin/myserver --background
    /build/bin/myclient --server 127.0.0.1
17
27.01.2020, 20:20

Если вам нужно игнорировать результат команды в Make , вы должны использовать оператор -следующим образом:

test: client server
    -pkill -f myserver
    myserver --background
    myclient --server 127.0.0.1

Таким образом, Make будет знать, что вам все равно, если pkillпотерпит неудачу, и вам не придется использовать ||без необходимости.

Вы также можете не печатать команду и вывод с помощью @-следующим образом:

test: client server
    @-pkill -f myserver
    myserver --background
    myclient --server 127.0.0.1
2
27.01.2020, 20:20

Теги

Похожие вопросы