Как мне предотвратить появление ‘grep’ в результатах ps?

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

Когда я ищу какой-то процесс, которого не существует, например,

$ 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 "${@:-^}"
}

Разбор кода, один пункт на строку кода:

  • Сохраните подробный вывод pslocal переменной, чтобы он был локальным для функции)
  • Отобразите первую строку (заголовок) в стандартной ошибке, чтобы результаты можно было дополнительно фильтровать, не затрагивая заголовок. Замена говорит: возьмите $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 в результатах ваших процессов. Все эти методы имеют свои преимущества и недостатки, и лучший выбор будет зависеть от ваших конкретных нужд и сценариев использования. Определите, какой способ лучше всего подходит для вас, и используйте его для упрощения и оптимизации работы с процессами в вашей системе.

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

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