- Вопрос или проблема
- Поиск процессов
- Ищете что-то другое?
- Ответ или решение
- 1. Использование квадратных скобок
- 2. Использование команды pgrep
- 3. Исключение grep из результатов
- 4. Использование командной подстановки
- 5. Альтернативные методы
- Метод с использованием суффикса
- Использование POSIX на других системах
- Заключение
Вопрос или проблема
Когда я ищу какой-то процесс, которого не существует, например,
$ ps aux | grep fnord
wayne 15745 0.0 0.0 13580 928 pts/6 S+ 03:58 0:00 grep fnord
Очевидно, мне не важно, что показывает grep – это также разумно, как и поиск процесса ps
!
Как я могу предотвратить появление grep в результатах?
Оказывается, есть решение, найденное в keychain.
$ ps aux | grep "[f]nord"
Поставив скобки вокруг буквы и кавычки вокруг строки, которую вы ищете, вы создаете регулярное выражение, которое говорит: “Найдите символ ‘f’, за которым следует ‘nord’.”
Но поскольку вы добавили скобки в шаблон, ‘f’ теперь будет за ‘]’, так что grep
не появится в списке результатов. Классно!
Еще один вариант, который я использую (особенно чтобы просто посмотреть, запущен ли процесс) – это команда pgrep
. Она ищет соответствующий процесс, но не выводит строку grep для поиска. Мне это нравится, потому что это быстрый способ поиска, без использования регулярных выражений или экранирования чего-либо.
pgrep fnord
Кроме того, чтобы вывести как идентификатор процесса, так и имя соответствующего процесса, используйте (спасибо phemmer)
pgrep -l fnord
Идеальное решение представлено BriGuy
pgrep fnord
Но если вы не хотите этого делать, вы можете просто исключить все строки, которые соответствуют grep, с помощью:
ps aux | grep -v grep | grep "fnord"
Не самое элегантное решение, но вы можете сделать так:
$ ps aux | grep fnord | grep -v grep
В zsh, grep fnord =(ps aux)
.
Идея заключается в том, чтобы сначала запустить ps aux
, поместить результат в файл, а затем использовать grep
по этому файлу. Только мы не имеем файла, так как используем “подстановку процессов” zsh.
Чтобы проиллюстрировать, попробуйте
ps aux > ps.txt
grep fnord ps.txt
rm ps.txt
Результат должен быть тем же.
Общий комментарий по некоторым другим ответам. Некоторые из них слишком сложны и/или длинны для ввода. Это не только вопрос правильности, это также должно быть удобно. Но это не означает, что некоторые из этих решений плохие; только они должны быть обернуты в мини-интерфейс, чтобы сделать их удобными.
⚠ Этот ответ специфичен для procps-ng. Смотрите ответ Уэйна для более общего решения.
Поиск процессов
Если вы просто ищете процессы fnord
, вы можете использовать опцию -C
для выбора по имени команды:
ps -C fnord
Это можно смешивать с опциями формата в стиле BSD и POSIX по вашему желанию. Смотрите страницу man ps для полного списка.
Ищете что-то другое?
Если вам нужно что-то более продвинутое, чем точный поиск по имени команды, не теряйте надежду! Это можно сделать и на стороне ps
в пайпе. Все, что нам нужно сделать, это сказать ps
исключить процессы grep
из результата :
ps -NC grep | grep 'fnord'
-C grep
выбирает все процессы grep, а -N
отменяет выбор. Это может быть использовано для поиска аргументов команд, части имени команды или более сложных регулярных выражений.
ps aux | grep $(echo fnord | sed "s/^\(.\)/[\1]/g")
Самый простой способ, не зависящий от оболочки, сделать это – сначала сохранить его в переменной:
PS_OUTPUT="$(ps aux)"; echo "$PS_OUTPUT" | grep fnord
Из моих файлов конфигурации, у меня есть версия без учета регистра, которая принимает параметры grep:
psl() {
local PS_OUTPUT="$(ps auxww)"
echo "${PS_OUTPUT%%$'\n'*}" >&2 # заголовок, в stderr, чтобы избежать пайпов
echo "${PS_OUTPUT#*$'\n'}" | grep -i "${@:-^}"
}
Разбор кода, один пункт на строку кода:
- Сохраните подробный вывод
ps
(вlocal
переменной, чтобы он был локальным для функции) - Отобразите первую строку (заголовок) в стандартной ошибке, чтобы результаты можно было дополнительно фильтровать, не затрагивая заголовок. Замена говорит: возьмите
$PS_OUTPUT
и удалите все после первого перевода строки (эквивалент регулярного выражения:s/\n.*$//msg
). Это предотвращает grep заголовка - Выведите вывод
ps
с чем угодно кроме первой строки (эквивалент регулярного выражения:s/^.*\n//m
) и grep его содержимое с-i
(без учета регистра) и все параметры, переданные этой функции (в случае отсутствия шаблона используйте^
для соответствия началу каждой строки)
Заметка: @EmanuelBerg’s grep fnord =(ps aux)
ответ, безусловно, самый элегантный, хотя он требует zsh
. Я недолго имел его в своих файлах конфигурации, но bash жалуется на эту синтаксис, несмотря на условие, которое должно предотвращать его оценку.
Мой ответ – это вариация типичного ответа для поиска “foobar” в списке ‘ps’. Аргумент “-A” для “ps” более переносим, чем “aux”, я верю, но это изменение не имеет значения для ответа. Типичный ответ выглядит так:
$ ps -A -ww | grep [f]oobar
Вместо этого я использую этот шаблон:
$ ps -A -ww | grep [^]]foobar
Основное преимущество заключается в том, что легче писать скрипты на основе этих шаблонов, потому что вы просто конкатенируете статическую строку “[^]]” с тем, что вы ищете. Вам не нужно вырезать первую букву строки, а затем вставлять ее между квадратными скобками, а затем снова конкатенировать. При написании скриптов в оболочке проще просто вставить “[^]]” перед искомым шаблоном. Извлечение подстроки в Bash – это неприятная вещь, так что моя вариация избегает этого. Эта вариация говорит показывать строки, где шаблон совпадает БЕЗ ведущей правой квадратной скобки ]. Поскольку шаблон поиска, чтобы исключить квадратную скобку, фактически добавляет квадратную скобку к шаблону, она никогда не совпадет сама с собой.
Вы можете написать переносимую команду ‘psgrep’ следующим образом. Здесь я учитываю различия между Linux, OS X BSD и другими. Это добавляет заголовки столбцов из ‘ps’, предоставляет более настраиваемый формат ‘ps’, который лучше соответствует моим потребностям, и отображает списки процессов очень широкими, чтобы не упустить никаких аргументов командной строки. Ну, большинство не упускается. Java, будучи Java, часто делает вещи самым худшим образом, поэтому некоторые java-сервисы могут выходить за пределы максимальной допустимой длины аргументов, которые таблица процессов может отслеживать. Я полагаю, это 1024 символа. Допустимая длина командной строки для запуска процесса гораздо больше, но таблица процессов ядра не заботится о том, чтобы отслеживать все, что длиннее 1К. Как только команда запущена, имя команды и список аргументов больше не нужны, поэтому то, что хранится в таблице процессов, является лишь информацией.
psgrep ()
{
pattern=[^]]${1};
case "$(uname -s)" in
Darwin)
ps -A -ww -o pid,ppid,nice,pri,pcpu,pmem,etime,user,wchan,stat,command | grep -i -e "^[[:space:]]*PID" -e ${pattern}
;;
Linux)
ps -A -ww -o pid,ppid,tid,nice,pri,pcpu,pmem,etime,user,wchan:20,stat,command | grep -i -e "^[[:space:]]*PID" -e ${pattern}
;;
*) # другие версии UNIX получают минимальную версию.
ps -A -ww | grep -i -e ${pattern}
;;
esac
}
Вот расширенная версия решения grep -v grep
, фильтрующая все процессы grep
, которые не работали более одной секунды, что является улучшением по сравнению с “просто отбрасывать все вхождения grep
“.
$ ps -ef | grep -vw "00:00:00 grep" | grep <searchTerm>
соответственно
$ ps aux | grep -vw "0:00 grep" | grep <searchTerm>
Это может быть не переносимо и зависит от фактического формата вывода вашей локальной команды ps
.
Вы можете захотеть объединить это с цветным выводом grep
для удобства:
$ alias grep='grep --color=auto'
Может быть, время использовать настоящую последовательность на этот раз. Использование пайпов делает это параллельным.
ps aux > f && grep tmpfs < f
Уродливо, потому что будет файл f
, но это не моя вина, что нет синтаксиса для последовательных процессов, где вы все еще хотите использовать вывод ранее запущенного процесса.
Предложение для синтаксиса последовательного оператора:
ps aux ||| grep tmpfs
Уже здесь много отличных ответов, и, возможно, не нужно еще одного, но я просто не могу удержаться… Что насчет использования подстановки команд через “here string”?:
grep fnord <<<$(ps aux)
Это гарантирует, что ps aux
завершится перед grep (через подстановку команд), а затем передает результат в stdin grep (через here string), так что grep никогда не появится в выводе ps aux
.
Команда pgrep, как уже упоминали другие, вернет PID (идентификатор процесса) процессов на основе имени и других атрибутов. Например,
pgrep -d, -u <username> <string>
вернет вам PID, разделенные запятой (,), всех процессов, чье имя совпадает и которые запущены пользователем <username>
. Вы можете использовать переключатель -x перед ним, чтобы вернуть только точные совпадения.
Если вы хотите получить больше информации об этих процессах (как подразумевается при запуске опций aux от ps), вы можете использовать опцию -p с ps, которая соответствует по PID. Так, например,
ps up $(pgrep -d, -u <username> <string>)
вернет подробную информацию о всех PID, соответствующих команде pgrep.
Вот простой пример, чтобы найти PID ssh-agent
для имени пользователя без отображения PID самого процесса grep
:
ps xu | grep "${USER}.*[ ]/usr/bin/ssh-agent" | awk '{print $1 $2;}'
Если вы хотите, например, убить ssh-agent
для текущего пользователя, вы можете использовать следующую команду:
kill `ps xu | grep "${USER}.*[ ]/usr/bin/ssh-agent" | awk '{print $2;}'`
Чтобы создать удобный псевдоним, добавьте в свой файл ~/.bashrc или ~/.zshrc следующий код:
function function1 () {
ps xu | grep "$1.*$2" | awk '{print $1" "$2" "$11;}'
}
alias mygrep="function1"
И чтобы использовать псевдоним, вот примеры, чтобы заставить всех изучить регулярные выражения:
. /etc/profile # чтобы сделать псевдоним доступным
mygrep ${USER} ${PROCESS_PATH}
mygrep ${USER} "[f]nord"
mygrep "[f]nord"
mygrep ".*[s]shd"
P.S. Я тестировал эти команды только на Ubuntu и Gentoo.
Использование опции -x (точное совпадение) сработало для меня. Я комбинировал это с -f (полная команда), чтобы точно сопоставить свой процесс с:
pgrep -x -f "path_i_used_when_starting/cmd params_i_used"
Развивая ответы @Emmanuel-Berg и @Adam-katz, вы можете использовать POSIX опцию “-f $file” вместе с “Подстановкой процессов” Bash “<( $cmd)”:
$ ps aux | grep -f <( echo fnord)
Шаблон передается grep
через псевдофайл, заполненный командой echo fnord
. Вы можете использовать эту удобную форму, которая позволяет задать несколько шаблонов (fnord
+ syslog
), а не только один:
$ alias psgrep='ps aux | grep -f <( echo -e "$a")'
$ a="fnord\nsyslog"; psgrep
Для ‘fnord’ оба регулярных выражения [f]nord или использование pgrep могут работать.
Но для общего использования регулярное выражение намного более гибкое, позволяя получить больше информации о выводе в случае, если вам нужно уточнить поиск. Это делает решение более надежным, чем то, что предлагает ‘pgrep’, возвращая только PID.
Представьте машину, на которой работает несколько экземпляров Tomcat с процессами, такими как:
tomcat 154304 1 8 10:43 ? 00:00:59 /usr/lib/jvm/jre/bin/java -Djava.util.logging.config.file=/somewhere/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Xms512M -Xmx1024M -server -XX:+UseParallelGC -Dignore.endorsed.dirs= -classpath ....
В этом случае ‘pgrep’ не будет надежным (если вообще будет работать) для идентификации точного процесса, который вам нужен.
С другой стороны:
ps -fea|grep "[j]ava"
вероятно, не будет достаточно точным, но позволит дальше обработать вывод для уточнения поиска
Мне часто нужно видеть полную командную строку, а также идентификатор процесса, чтобы получить подсказки о том, как был запущен процесс или где находится конфигурация. Для этого я использую pgrep -a
, который предоставляет это, не отображая никакой информации о команде grep.
Как упоминается в документации, -a
будет:
| -a, –list-full
Список полной командной строки, а также идентификатора процесса. (только pgrep.)
Например, запуск:
pgrep -a dockerd
вернет что-то вроде
111 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --config-file /etc/docker/a.json
Вы можете сделать это легко, просто определив ALIAS в своем .bashrc
следующим образом:
alias grep='grep -v grep | grep'
Ответ или решение
Чтобы предотвратить появление grep
в результатах команды ps
, существует несколько эффективных подходов, которые можно использовать. Ниже приведены основные методы, которые позволят вам избегать нежелательных строк с grep
, а также некоторые примеры улучшенных команд для поиска процессов.
1. Использование квадратных скобок
Одним из самых популярных способов является использование квадратных скобок, чтобы обернуть первую букву искомого слова. Это метод работает, поскольку grep
не будет совпадать с самим собой. Например:
ps aux | grep "[f]nord"
Здесь grep
ищет строки, содержащие fnord
, но не совпадает с выражением grep [f]nord
, поскольку буква f
заключена в квадратные скобки.
2. Использование команды pgrep
Команда pgrep
может стать вашим лучшим другом, когда вы ищете процессы по имени. Она значительно удобнее, так как автоматически не показывает процессы grep
в результатах:
pgrep fnord
Если вы хотите получить больше информации о процессах, можно использовать ключ -l
, который отображает как идентификатор процесса, так и его название:
pgrep -l fnord
3. Исключение grep
из результатов
Если вы хотите использовать ps
и всё же применить grep
, вы можете отфильтровать все строки с grep
, используя ключ -v
, что позволяет исключить результаты:
ps aux | grep "fnord" | grep -v grep
Этот метод не самый элегантный, но он работает. Однако будьте внимательны, так как он может привести к путанице, если в вашем списке процессов есть другие команды с именем grep
.
4. Использование командной подстановки
Вы можете сохранить вывод команды в переменную, а затем передать его в grep
:
PS_OUTPUT="$(ps aux)"; echo "$PS_OUTPUT" | grep fnord
Этот подход позволяет избежать появления самого процесса grep
, поскольку команда выполняется последовательно.
5. Альтернативные методы
Метод с использованием суффикса
Некоторые пользователи используют метод, при котором перед основной командой добавляется sed
, чтобы исключить нежелательные процессы:
ps aux | grep "fnord" | sed '/[g]rep/d'
Этот подход также является рабочим, однако он более сложен и может усложнить чтение команд.
Использование POSIX на других системах
Если вам нужно более универсальное решение, например, для кросс-совместимого использования на Unix-подобных системах, вы можете использовать:
ps -C fnord
Этот подход позволяет точно искать процессы по имени, исключая grep
.
Заключение
В приведенных выше примерах представлены несколько методов предотвращения отображения grep
в результатах ваших процессов. Все эти методы имеют свои преимущества и недостатки, и лучший выбор будет зависеть от ваших конкретных нужд и сценариев использования. Определите, какой способ лучше всего подходит для вас, и используйте его для упрощения и оптимизации работы с процессами в вашей системе.