Почему ps o / p перечисляет процесс grep после канала? - PullRequest
17 голосов
/ 01 августа 2011

Когда я делаю

$ ps -ef | grep cron

Я получаю

root      1036     1  0 Jul28 ?        00:00:00 cron
abc    21025 14334  0 19:15 pts/2    00:00:00 grep --color=auto cron

Мой вопрос: почему я вижу вторую строку? Насколько я понимаю, ps перечисляет процессы и передает список в grep. grep даже не запустился, пока ps перечисляет процессы, тогда почему grep процесс указан в o / p?

Второй вопрос по теме:

Когда я делаю

$ ps -ef | grep [c]ron

Я получаю только

root      1036     1  0 Jul28 ?        00:00:00 cron

В чем разница между первым и вторым grep казнями?

Ответы [ 7 ]

22 голосов
/ 14 марта 2012

При выполнении команды:

ps -ef | grep cron

оболочка, которую вы используете

(... я предполагаю, что bash в вашем случае из-за атрибута цвета grep, я думаю, что вы работаете с системой GNU, такой как дистрибутив linux, но то же самое относится и к другим unix / shell ...)

выполнит вызов pipe(), чтобы создать FIFO, затем он fork() (создаст рабочую копию самого себя). Это создаст новый дочерний процесс. Этот новый сгенерированный дочерний процесс close() будет использовать стандартный дескриптор выходного файла (fd 1) и присоединит fd 1 к стороне записи канала, созданного родительским процессом (оболочкой, в которой вы выполнили команду). Это возможно, потому что системный вызов fork() будет поддерживать для каждого действительный дескриптор открытого файла (в данном случае это канал fd). После этого будет exec() первая (в вашем случае) команда ps, найденная в вашей переменной окружения PATH. При вызове exec() процесс станет командой, которую вы выполнили.

Итак, теперь у вас есть процесс оболочки с дочерним элементом, который в вашем случае является командой ps с -ef атрибутами.

В этот момент родитель (оболочка) снова fork() s. Этот недавно сгенерированный дочерний процесс close() имеет свой стандартный дескриптор входного файла (fd 0) и присоединяет fd 0 к стороне чтения канала, созданного родительским процессом (оболочкой, в которой вы выполнили команду).

После этого будет exec() первая (в вашем случае) grep команда, найденная в переменной среды PATH.

Теперь у вас есть процесс оболочки с двумя дочерними элементами (которые являются братьями и сестрами), где первый - это команда ps с атрибутами -ef, а второй - это команда grep с атрибутом cron. Сторона чтения канала прикреплена к STDIN команды grep, а сторона записи - к STDOUT команды ps: стандартный вывод команды ps присоединен к стандартный ввод команды grep.

Поскольку ps написано для отправки стандартной выходной информации о каждом запущенном процессе, а grep написано для получения на его стандартном вводе того, что должно соответствовать заданному шаблону, у вас будет ответ на ваш первый вопрос :

  1. оболочка работает: ps -ef;
  2. оболочка работает: grep cron;
  3. ps отправляет данные (которые даже содержат строку "grep cron") на grep
  4. grep соответствует шаблону поиска из STDIN и соответствует строке "grep cron" из-за атрибута "cron", который вы передали grep: вы указываете grep, что соответствует "cron "строка и это делает, потому что" grep cron "- это строка, возвращаемая ps в то время, когда grep начала свое выполнение.

При выполнении:

ps -ef | grep '[c]ron'

переданный атрибут указывает grep на совпадение с чем-то, содержащим «c» и «ron». Как и в первом примере, но в этом случае он сломает строку соответствия, возвращаемую ps, потому что:

  1. оболочка работает: ps -ef;
  2. оболочка работает: grep [c]ron;
  3. ps отправляет данные (которые даже содержат строку grep [c]ron) на grep
  4. grep не соответствует шаблону поиска в stdin, поскольку строка, содержащая «c», за которой следует «ron», не найдена, но обнаружена строка, содержащая «c», за которой следует «] ron»

GNU grep не имеет ограничения на совпадение строк, а на некоторых платформах (я думаю, Solaris, HPUX, aix) предел строки задается переменной "$ COLUMN" или шириной экрана терминала.

Надеюсь, этот длинный ответ немного прояснит процесс оболочки.

Совет:

ps -ef | grep cron | grep -v grep
8 голосов
/ 13 марта 2012

В вашей команде

ps -ef | grep 'cron'

Linux выполняет команду "grep" перед командой ps -ef.Затем Linux отображает стандартный вывод (STDOUT) «ps -ef» на стандартный ввод (STDIN) команды grep.

Он не выполняет команду ps, сохраняет результат в памяти и передает ихэто grep.Подумай об этом, с чего бы это?Представьте себе, если бы вы передавали сто гигабайт данных?

Править В отношении вашего второго вопроса:

В grep (и большинстве механизмов регулярных выражений) вы можете указатьскобки, чтобы сообщить, что вы будете принимать любой символ в скобках.Таким образом, запись [c] означает, что он примет любой символ, но указан только c.Точно так же вы можете сделать любую другую комбинацию символов.

ps aux | grep cron
root      1079  0.0  0.0  18976  1032 ?        Ss   Mar08   0:00 cron
root     23744  0.0  0.0  14564   900 pts/0    S+   21:13   0:00 grep --color=auto cron

^ Это соответствует самому себе, потому что ваша собственная команда содержит "cron"

ps aux | grep [c]ron
root      1079  0.0  0.0  18976  1032 ?        Ss   Mar08   0:00 cron

Это соответствует cron, потому что cron содержит ac, а затем "Рон".Это не соответствует вашему запросу, потому что ваш запрос [c] ron

Вы можете поместить в скобки все, что захотите, если в нем содержится c:

ps aux | grep [cbcdefadq]ron
root      1079  0.0  0.0  18976  1032 ?        Ss   Mar08   0:00 cron

Есливы удаляете C, он не будет совпадать, потому что "cron" начинается с ac:

ps aux | grep [abedf]ron

^ Нет результатов

Edit 2

Чтобы повторить мысль, вы можете делать всякие сумасшедшие вещи с помощью grep.Нет никакого смысла в выборе первого персонажа, с которым это будет сделано.

ps aux | grep [c][ro][ro][n]
root      1079  0.0  0.0  18976  1032 ?        Ss   Mar08   0:00 cron
7 голосов
/ 01 августа 2011

Оболочка создает ваш конвейер с серией вызовов fork(), pipe() и exec(). В зависимости от оболочки любая ее часть может быть построена первой. Так что grep может быть запущен еще до того, как ps запустится. Или, даже если ps запускается первым, он будет записывать в буфер канала 4k ядра и в конечном итоге будет блокировать (при печати строки вывода процесса), пока grep не запустится и не начнет использовать данные в канале. В последнем случае, если ps может начать и закончить до того, как grep даже запустится, вы можете не увидеть grep cron в выходных данных. Возможно, вы уже заметили этот недетерминизм в игре.

2 голосов
/ 15 марта 2012

Вы писали: "Насколько я понимаю, ps перечисляет процессы и передает список в grep. Grep даже не запускается, пока ps перечисляет процессы".

Ваше понимание неверно.

Это не так, как работает конвейер. Оболочка не запускает первую команду до завершения, запоминает вывод первой команды, а затем после этого запускает следующую команду, используя эти данные в качестве входных данных. Нет. Вместо этого выполняются оба процесса, а их входы / выходы подключены . Как писал Бен Джексон, нет ничего, чтобы особо гарантировать, что процессы будут выполняться одновременно, если они оба очень недолговечны и если ядро ​​может с комфортом управлять небольшим объемом данных, проходящих через соединение. В этом случае это действительно может произойти так, как вы ожидаете, только случайно. Но имейте в виду, что они работают параллельно.

Если вам нужны официальные источники, как насчет man-страницы bash:

  A pipeline is a sequence of one or more commands separated by the character |.  The format for a pipeline is:

         [time [-p]] [ ! ] command [ | command2 ... ]

  The  standard  output  of command is connected via a pipe to the standard input of command2.  This connection is
  performed before any redirections specified by the command (see REDIRECTION below).

  ...

  Each command in a pipeline is executed as a separate process (i.e., in a subshell).

Что касается вашего второго вопроса (который на самом деле не имеет никакого отношения к сожалению, извините), вы просто описываете особенности работы регулярных выражений. Регулярное выражение cron соответствует строке cron. Регулярное выражение [c]ron не не соответствует строке [c]ron. Таким образом, первая команда grep окажется в списке процессов, а вторая - нет.

1 голос
/ 01 августа 2011

На ваш фактический вопрос ответили другие, но я предложу совет: если вы не хотите видеть процесс grep в списке, вы можете сделать это следующим образом:

$ ps -ef | grep [c]ron
0 голосов
/ 25 ноября 2013

pgrep иногда лучше, чем ps -ef | grep word, поскольку исключает grep. Попробуйте

pgrep -f bash
pgrep -lf bash
0 голосов
/ 11 ноября 2013
$ ps -ef | grep cron

Linux Shell всегда выполняет команду справа налево. поэтому перед выполнением ps -ef grep cron уже выполнен, поэтому o / p show - это сама команда.

$ ps -ef | grep [c]ron

Но в этом u указан grep ron, за которым следует только c. Итак, o / p без командной строки, потому что в команде есть [c] ron.

...