Установка разделителя столбца PS в OSX (BSD)

Я работаю над скриптом, который должен анализировать данные, возвращаемые командой ps. Я знаю, что в Redhat/Centos легко указать разделитель столбцов, но с BSD-версия PS, это не так просто.

Я знаю, что можно было бы использовать awk, sed или tr для замены пробелов любым символом, но допустим, формат имеет args или comm где-то посередине, вывод будет таким:

$ ps -o pid,ppid,args,user | head
  PID  PPID ARGS                                                             USER
60140   494 /Applications/iTerm.app/Contents/MacOS/iTerm2 --server login -fp jdoe
60144 60141 -bash                                                            jdoe
55574   494 /Applications/iTerm.app/Contents/MacOS/iTerm2 --server login -fp jdoe
55576 55575 -bash                                                            jdoe
20710   494 /Applications/iTerm.app/Contents/MacOS/iTerm2 --server login -fp jdoe
20712 20711 -bash                                                            jdoe
66703   494 /Applications/iTerm.app/Contents/MacOS/iTerm2 --server login -fp jdoe
66707 66704 -bash                                                            jdoe
66881   494 /Applications/iTerm.app/Contents/MacOS/iTerm2 --server login -fp jdoe

Как видите, данные в столбце args могут содержать пробелы, что сбивает все с толку.

Что действительно раздражает, так это то, что я на самом деле нашел решение, которое, казалось, работает просто отлично, без необходимости делать что-то вроде добавления args в конец вывода, но я не могу вспомнить решение или найти его снова.

Я подумал, что, возможно, можно было бы использовать строку заголовка столбца для определения ширины столбца, поскольку заголовки выравниваются с данными столбца, но я уверен, что есть более простое решение.

Любая помощь будет оценена по достоинству. Спасибо!


person Justin    schedule 28.02.2017    source источник
comment
Почему вы не можете просто args в качестве последнего столбца и читать данные с помощью Awk? Вы можете использовать его таким образом?   -  person Inian    schedule 28.02.2017
comment
Единственным надежным разделителем будет нулевой символ.   -  person chepner    schedule 28.02.2017
comment
Что вы на самом деле хотите СДЕЛАТЬ с этими данными? Какова ваша конечная игра? Давайте посмотрим, сможем ли мы выяснить, как достичь вашей цели, а не просто отправить вас на неправильный путь.   -  person ghoti    schedule 04.03.2017
comment
Кроме того, ссылка на справочную страницу в вашем вопросе на самом деле представляет собой версию ps для SuSE Linux, а не версию OS X или любую текущую версию FreeBSD.   -  person ghoti    schedule 04.03.2017
comment
Возможно, используйте homebrew для установки GNU-версии ps.   -  person Mark Setchell    schedule 04.03.2017


Ответы (3)


ps -o pid,ppid,args,user \
 awk -v Rpl='_' '
    # line but the header
    NR > 1 {
       p = $1
       P = $2
       u = $NF
       A = $0
         sub( "^[[:blank:]*" p "[[:blank:]*" P "[[:blank:]*", "", A)
         sub( "[[:blank:]*" u "[[:blank:]*$", "", A)
       gsub( " ", Rpl, A)

       # recreate the line
       $0 = sprintf( "%d\t%d\t%s\t%s\n", p, P, A, u)
       }

    # print the line
    7
    '

Заметки:

  • Я использую дополнительный код, чем необходимо, чтобы показать, где и как брать информацию, p, P и U могут быть напрямую равны $1,...
  • Я воссоздаю линию, вы можете распечатать ее напрямую. Это в том случае, если вы хотите обработать строку или контент и быть более явным.
  • 7 - это не 0 (частная шутка, 1 достаточно и не сбивает с толку), у которых по умолчанию есть действие для печати текущей строки.
  • Содержимое Rpl (назначаемое вне awk, чтобы разрешить пакетное взаимодействие) — это шаблон, который заменит пространство, которое может быть любым (пустое также доступно).
  • я использую \t в качестве нового разделителя, может быть что угодно.
  • адаптироваться, если используется другое поле ps, но не будет работать, если внутри нескольких есть потенциальное пространство.
person NeronLeVelu    schedule 01.03.2017
comment
Некоторые значения в столбце args будут содержать пробелы, которые объединяются вместе. Вы знаете, как это исправить? Может быть, в столбце args замените пробелы чем-то вроде ||, затем при их выводе замените || пробелом. Но в остальном, это определенно лучше, чем то, что у меня было. - person Justin; 02.03.2017
comment
Изменить: я не полностью изучил логику, прежде чем публиковать вышеизложенное. Но если столбцы перемещаются, это не сработает, верно? Я должен был опубликовать это, но мне нужно иметь возможность перемещать столбцы. - person Justin; 02.03.2017
comment
единственное ограничение i, чтобы определить, где находится разнесенное поле, и если есть только 1, вы можете занять место других, как здесь. Самое простое, если это возможно, - это заказать поле с интервалом (здесь ARGS) на последнем месте, чтобы другие было очень легко поймать и отфильтровать. - person NeronLeVelu; 03.03.2017

Что ж, поскольку ваш bsd ps не поддерживает параметр --libxo, как было рекомендовано в моем предыдущем ответе, вы всегда можете использовать классический подход bash, поместив аргументы с интервалом в конце.

Затем вы можете использовать цикл для чтения всего вывода ps в массиве, а затем вы можете распечатать задачи в любом порядке, который вы хотите, настроив печать соответствующих элементов массива.

Но для «разбора» вам нужно оставить аргументы с интервалами в конце. Для печати вы просто печатаете массив в другом порядке.

Посмотрите этот тест и обратите внимание на пробелы в элементе массива №7,11,15:

$ while read -r pid ppid user args;do \
psdata+=( "$pid" "$ppid" "$user" "$args" ); \
done< <(ps -o pid,ppid,user,args)

$ declare -p psdata  #let's ask bash to print the array for us
declare -a psdata=([0]="PID" [1]="PPID" [2]="USER" [3]="COMMAND" [4]="769" \
[5]="1" [6]="root" [7]="/usr/libexec/getty Pc ttyv0" [8]="770" [9]="1" \
[10]="root" [11]="/usr/libexec/getty Pc ttyv1" [12]="771" [13]="1" [14]="root" \
[15]="/usr/libexec/getty Pc ttyv2" [16]="772" [17]="1" [18]="root" \
# more items here
person George Vasiliou    schedule 04.03.2017

Утилита PS последней версии FreeBSD11 имеет параметр --libxo, который можно использовать для форматирования вывода ps в xml, text, json и т. д. Хотя этот параметр будет недоступен в утилите ps, которая поставляется из более ранней версии bsd (например, openbsd 6 или freebsd менее 11). ).

Если доступен --libxo, одним из обходных путей может быть использование ps --libxo json, а затем использование jq для получения необходимых вам значений или использование другого инструмента, такого как sed.

Посмотрите этот тест:

$ ps --libxo json -o pid,args |tr '}' '\n' |sed 's/["{:]//g;s/arguments//g;s/pid//g;s/^,//g'

804,-csh (csh)
813,dbus-launch --sh-syntax --exit-with-session
816,xinit /usr/local/etc/xdg/xfce4/xinitrc
817,X 0 (Xorg)
819,sh /usr/local/etc/xdg/xfce4/xinitrc
825,xfce4-session
.....................................................

Вы можете дополнительно cut отформатировать stram и извлечь поля на основе разделителя-запятой (т.е. канал над выводом |cut -d, -f2 даст вам только аргументы)

Конечно, если вы умеете работать с jq, вам не нужны все эти пайпы и seds, вы можете извлекать поля прямо из json-потока.

Кроме того, вы можете посмотреть в man xo_parse_args дополнительные параметры --libxo параметра ps.

person George Vasiliou    schedule 01.03.2017
comment
Нет, я на OSX, и нет опции --libxo, по крайней мере, в моей версии. gist.github.com/jhyland87/6ff0266abc9a9b57690ab28dfc18c180 - person Justin; 02.03.2017
comment
@Justin - К вашему сведению, команда OSX ps основана на ps из FreeBSD 6.0 (выпущенной в 2005 г.), которая не включает параметр --libxo. Эта опция на самом деле была добавлена ​​во FreeBSD 11, который был выпущен в 2016 году. - person ghoti; 04.03.2017