Вопрос или проблема
Мне нужно изменить формат вывода следующей команды с помощью awk для статических и динамических номеров столбцов:
ps -eopid,lstart,cmd | grep java | grep -v grep
Следующим будет пример ввода для команды awk:
17524 Wed May 9 08:50:37 2018 /opt/java/latest/bin/java -client -Xms256m -Xmx512m -XX:CompileThreshold=8000 -XX:PermSize=128m -XX:MaxPermSize=256m -Dweblogic.Name=AdminServer -Djava.security.policy=/app/oracle/wls1036/wlserver_10.3/server/lib/weblogic.policy -Dweblogic.system.BootIdentityFile=/projects/domainName/servers/AdminServer/security/boot.properties -Dweblogic.nodemanager.ServiceEnabled=true -Xverify:none -da -Dplatform.home=/app/oracle/wls1036/wlserver_10.3 -Dwls.home=/app/oracle/wls1036/wlserver_10.3/server -Dweblogic.home=/app/oracle/wls1036/wlserver_10.3/server -Ddomain.home=/projects/domainName -Does.client.home=/app/oracle/wls1036/oesclient -Doracle.home=/app/oracle/wls1036/oesclient -Doracle.security.jps.config=/projects/mydomain/config/oeswlssmconfig/AdminServer/jps-config.xml -Dweblogic.management.discover=true -Dwlw.iterativeDev= -Dwlw.testConsole= -Dwlw.logErrorsToConsole= -Dweblogic.ext.dirs=/app/oracle/wls1036/patch_wls1036/profiles/default/sysext_manifest_classpath:/app/oracle/wls1036/patch_ocp371/profiles/default/sysext_manifest_classpath weblogic.Server
Выходной пример:
24519 Wed May 9 23:50:09 2018 -Dweblogic.Name=AdminServer
Проблема: мне удается напечатать значение начального PID, даты и времени запуска на основе номера столбца с помощью awk, но номер столбца для последнего значения может отличаться в разных случаях (например: столбец 9 в одном выводе и столбец 17 в другом). Как я могу напечатать последнее значение, ища соответствующий номер столбца, содержащий ключевое слово “-Dweblogic.Name=”, и добавить его к существующему выводу. Объединение вывода для номеров столбцов и поиска по столбцам вызывает исключение.
Любой более простой способ отформатировать этот вывод также приветствуется с использованием (sed,grep,cut и т. д.).
Возможно, вы можете искать Dweblogic с помощью grep, а затем с помощью sed
search="-Dweblogic.Name="
ps -eopid,lstart,cmd | \
grep "java.*$search" | \
sed -E 's#([^/]* )/.*('"$search"'[^ ]*).*#\1\2#'
Чтобы получить столбец, используйте цикл
| awk '{for(i=NF;i>1;i--)
if ( $i ~ /-Dweblogic.name/ ) { wln=$i; break } ;
printf "... %s ...",wln}'
где
NF
представляет собой количество полейfor( )
конструкция будет проходить с конца строки к началу$i ~ /-Dweblogic.name/
соответствует -Dweblogic.name=admin1 , -Dweblogic.name=otheradmin (вы можете использовать /^-D/, чтобы не совпадать с самим собой)
Могу я предложить вам заменить grep java | grep -v grep
на grep [j]ava
, что не будет искать себя (и удивит коллег), или
| awk '/java/ {...} '
или, чтобы иметь минимальное количество аргументов :
| awk '/java/ && NF>10 { ... }'
Используя Raku (ранее известный как Perl_6)
raku -ne 'my @a = .words; put "@a[0..5] @a.grep(/^ \-Dweblogic\.Name\= /)" if .words > 6;'
Пример ввода:
17524 Wed May 9 08:50:37 2018 /opt/java/latest/bin/java -client -Xms256m -Xmx512m -XX:CompileThreshold=8000 -XX:PermSize=128m -XX:MaxPermSize=256m -Dweblogic.Name=AdminServer -Djava.security.policy=/app/oracle/wls1036/wlserver_10.3/server/lib/weblogic.policy -Dweblogic.system.BootIdentityFile=/projects/domainName/servers/AdminServer/security/boot.properties -Dweblogic.nodemanager.ServiceEnabled=true -Xverify:none -da -Dplatform.home=/app/oracle/wls1036/wlserver_10.3 -Dwls.home=/app/oracle/wls1036/wlserver_10.3/server -Dweblogic.home=/app/oracle/wls1036/wlserver_10.3/server -Ddomain.home=/projects/domainName -Does.client.home=/app/oracle/wls1036/oesclient -Doracle.home=/app/oracle/wls1036/oesclient -Doracle.security.jps.config=/projects/mydomain/config/oeswlssmconfig/AdminServer/jps-config.xml -Dweblogic.management.discover=true -Dwlw.iterativeDev= -Dwlw.testConsole= -Dwlw.logErrorsToConsole= -Dweblogic.ext.dirs=/app/oracle/wls1036/patch_wls1036/profiles/default/sysext_manifest_classpath:/app/oracle/wls1036/patch_ocp371/profiles/default/sysext_manifest_classpath weblogic.Server
Пример вывода:
17524 Wed May 9 08:50:37 2018 -Dweblogic.Name=AdminServer
Кратко, -ne
построчный ввод разбивается на слова, разделенные пробелами words
, и присваивается массиву @a
. Затем первые 6 столбцов (слова [0..5]
) выводятся, за ними следует grep
для полных слов, которые соответствуют регулярному выражению /^ \-Dweblogic\.Name\= /
(также можно написать: /^ "-Dweblogic.Name=" /
).
Приведенный выше код обрабатывает короткие/пустые строки во входных данных, однако он выводит первые 6 столбцов (PID и метку времени), даже если /^ \-Dweblogic\.Name\= /
не найден. Гораздо лучше использовать код ниже, который решает эту проблему, используя переменную темы $_
Raku:
raku -ne 'my @a = .words; $_ = @a.grep(/^ \-Dweblogic\.Name\= /); put "@a[0..5] $_" if $_;'
Ответ или решение
Для решения задачи форматирования вывода команды, можно использовать инструмент awk
, который прекрасно подходит для работы с текстовыми данными. В данном случае вам необходимо вывести первые три столбца, соответствующие PID (идентификатор процесса), времени старта и команды, а также добавить значение, которое содержит специфический ключевой параметр -Dweblogic.Name=
. Поскольку это значение может находиться в разных столбцах в зависимости от формата строки, мы будем использовать awk
, чтобы обойти эту проблему.
Пример использования команды awk
Вы можете использовать следующую команду, которая сначала отфильтрует процессы, связанные с Java, и затем с помощью awk
отформатирует вывод:
ps -eopid,lstart,cmd | grep java | awk '{for(i=NF;i>0;i--) if($i ~ /^-Dweblogic\.Name=/) {dName=$i; break}} NF > 0 {printf "%s %s %s %s\n", $1, $2, $3, dName}'
Пояснение к команде:
ps -eopid,lstart,cmd
: Выводит все процессы с указанием их PID, времени старта и команд, которые их запустили.grep java
: Отфильтровывает только те строки, которые содержат словоjava
.awk
: Основное действие происходит именно здесь.- Цикл
for(i=NF;i>0;i--)
: Обходит все поля строки с конца к началу (в переменнойNF
хранится количество полей). if($i ~ /^-Dweblogic\.Name=/)
: Проверяет, содержится ли в текущем поле ключевой параметр-Dweblogic.Name=
.dName=$i; break
: Если ключ найден, сохраняем его значение в переменнойdName
и выходим из цикла.printf
: Форматирует вывод, где$1
,$2
,$3
— это PID, дата и время; аdName
— это значение ключа.
- Цикл
Применение альтернативных инструментов
Если вам необходима альтернатива awk
, вы можете рассмотреть использование sed
и grep
. Например, можно использовать следующую команду:
search="-Dweblogic.Name="
ps -eopid,lstart,cmd | grep "java.*$search" | sed -E "s#([^ ]* [^ ]*) .*($search[^ ]*)#\1 \2#"
Пояснение:
sed -E
: Включает поддержку расширенных регулярных выражений.s#([^ ]* [^ ]*) .*($search[^ ]*)#\1 \2#
: Заменяет всю строку на первые два поля и соответствующее значение переменнойsearch
, используя захватывающую группу.
Заметки о производительности
Существуют различные подходы к фильтрации и форматированию вывода, выбирайте тот, который лучше всего отвечает вашим требованиям. Ваша конечная цель может потребовать и других настроек, особенно если формат входных данных может изменяться или если необходимо обрабатывать несколько уровней вложенных команд.
Заключение
Предложенные решения позволяют гибко обрабатывать и форматировать выходные данные любой команды. Используя возможности фильтрации grep
, обработки текста с помощью awk
или sed
, можно добиться нужного результата. Экспериментируйте с командами в вашей среде, чтобы найти оптимальный подход для ваших задач.