Как правильно получить PID процесса, связанного с Java, с использованием ps aux? И как можно добавить заголовок с именем столбца в вывод?

Вопрос или проблема

Я не системный администратор (я разработчик программного обеспечения) и у меня есть следующий вопрос.

Выполняя эту команду, я могу увидеть список первых 10 процессов, работающих на моей системе (исправьте меня, если я ошибаюсь):

[email protected] [~/FOLDER]# ps aux | head -10
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0 191292  3892 ?        Ss    2021  21:29 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
root         2  0.0  0.0      0     0 ?        S     2021   0:00 [kthreadd]
root         4  0.0  0.0      0     0 ?        S<    2021   0:00 [kworker/0:0H]
root         6  0.0  0.0      0     0 ?        S     2021   2:17 [ksoftirqd/0]
root         7  0.0  0.0      0     0 ?        S     2021   0:10 [migration/0]
root         8  0.0  0.0      0     0 ?        S     2021   0:00 [rcu_bh]
root         9  0.1  0.0      0     0 ?        S     2021  71:37 [rcu_sched]
root        10  0.0  0.0      0     0 ?        S<    2021   0:00 [lru-add-drain]
root        11  0.0  0.0      0     0 ?        S     2021   0:56 [watchdog/0]

Так что второй столбец – это PID, идентифицирующий процесс (я могу использовать его, чтобы завершить процесс).

Затем я попытался выполнить эту команду, чтобы получить все работающие процессы, связанные с JAVA:

[email protected] [~/FOLDER]# ps aux | grep java
webadmin 22316  0.0  0.0 112812   980 pts/0    S+   18:21   0:00 grep --color=auto java

По сути, я фильтрую только строку, связанную с java.

И вот вопрос. PID всегда находится во втором столбце?

Можно ли добавить заголовок, содержащий имя столбца, как в первом примере?

Краткий ответ: не используйте ps aux для этого.

Обычно такие процессы запускаются как сервисы, и их PID отслеживается менеджером служб (например, systemd; Upstart; supervisord; Monit…). Если цель заключается в том, чтобы проверить, работает ли служба, – менеджер службы может на это ответить. (Например, systemctl is-active MyApp.) Если цель – перезапустить службу, если она не работает, или предотвратить одновременный запуск службы – это задача менеджера служб.

В ситуациях, когда процесс нельзя запустить как службу, его PID должен быть немедленно записан при запуске в файл PID – это может сделать либо само приложение, либо загрузчик. (Например, java -jar myapp.jar & echo $! > java.pid.)

Когда вам действительно нужно найти все работающие процессы, используйте команду pgrep. Например, чтобы найти все процессы Java, используйте pgrep java, а чтобы найти все процессы, упоминающие MyApp.jar, используйте pgrep -f MyApp.jar. (Добавьте опцию -a, чтобы увидеть команду, например: pgrep -a java.) Это не вызовет проблему с возвращением самого grep, как это делает ps|grep.

Если вы абсолютно должны использовать ps, то уточните точные столбцы, которые вы хотите. Теперь опция u уже запрашивает конкретный формат с определенными столбцами в определенном порядке – но если вам нужен только PID, опция o позволяет получить только PID. Например, ps axo pid,cmd всегда возвращает ровно два столбца: PID и команду, в этом порядке.

Чтобы найти только PID, pgrep часто лучше, чем ps.

Теперь я предполагаю, что вы точно знаете, что хотите, вы действительно хотите ps и хотите заголовок. Эта задача может быть решена с помощью sed:

ps aux | sed -n '1p; /java/p'

Обратите внимание, что ваш ps … | grep … вероятно, находит сам grep. Аналогично, моя команда находит sed. Вы можете избежать этого, используя регулярное выражение, эквивалентное java, но не содержащее java. Пример:

ps aux | sed -n '1p; /[j]ava/p'

Если вы хотите использовать grep (например, из-за его способности добавлять цвет), может показаться, что следующее должно работать:

# недостаток, не используйте это
ps aux | { head -n 1; grep '[j]ava'; }

Это нецелесообразно, потому что head может прочитать слишком много, и нет возможности вернуть излишне прочитанные данные, чтобы grep смог их считать. read в этом плане лучше, он читает по одному символу за раз, поэтому может надежно прочитать ровно одну строку:

ps aux | (IFS= read -r line; printf '%s\n' "$line"; grep '[j]ava')

Обратите внимание, что я принудительно создал подпроцесс, так что переменная умирает вместе с ним, и основная оболочка не затрагивается*.


* Оболочки могут запускать последнюю часть конвейера не в подпроцессе или неявно в подпроцессе. read line не в подпроцессе установит переменную line в основной оболочке. А что если переменная уже существует и содержит важное значение? Принуждая к созданию подпроцесса, мы защищаем состояние основной оболочки, независимо от того, как будет вести себя основная оболочка.

Ответ или решение

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

1. Извлечение PID процесса Java

Чтобы увидеть список всех запущенных процессов Java, можно использовать следующую команду:

ps aux | grep '[j]ava'

В этой команде использование [j]ava помогает избежать ситуации, когда команда grep сама появляется в выводе. Это связано с тем, что при поиске строки "java" сама команда grep java также будет показана, что не является желаемым результатом.

2. Заголовок с именами столбцов

Если вам нужно сформировать вывод так, чтобы он включал заголовки, вы можете сделать это с помощью утилиты sed или через другой метод. Вот пример:

ps aux | sed -n '1p; /[j]ava/p'

В данной команде sed выводит первую строку (заголовок) и затем строки, содержащие "java".

3. Использование команды pgrep

Если ваша основная цель – только получить PID, более предпочтительно использовать команду pgrep, которая предназначена именно для этой цели:

pgrep java

Эта команда вернет только PID всех процессов, связанных с Java, и не будет включать саму команду поиска в результаты.

4. Уточнение вывода с ps и добавление заголовков

Если вы хотите использовать ps и если вам нужно вывести только определенные столбцы (например, PID и команду), вы можете сделать это следующим образом:

ps -eo pid,cmd | grep '[j]ava'

Здесь -eo pid,cmd указывает на вывод только определенных столбцов с PID и командой.

5. Оптимизированный вывод с заголовками

Если вы хотите оставить заголовки в выводе, вы можете использовать следующий подход с grep и head:

{ ps -eo pid,cmd | head -n 1; ps -eo pid,cmd | grep '[j]ava'; }

Этот подход работает правильно, поскольку сначала выводится строка заголовка, а затем результаты поиска.

Заключение

На практике извлечение PID процессов Java может быть сделано несколькими способами, включая использование pgrep для простоты и прямоты. Если вам необходимо учитывать заголовки, использование комбинаций с sed или head может помочь. Помните, что старайтесь избегать утечек памяти, связанных с отображением ненужных строк, таких как сам grep.

Оцените материал
Добавить комментарий

Капча загружается...