Почему ps o/p перечисляет процесс grep после трубы?
Когда я делаю
$ 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
исполнениями?
Ответы
Ответ 1
При выполнении команды:
ps -ef | grep cron
оболочку, которую вы используете
(... Я предполагаю, что bash в вашем случае из-за атрибута цвета grep. Я думаю, что вы используете систему gnu, такую как дистрибутив linux, но это то же самое на других unix/shell... )
выполнит вызов pipe()
для создания FIFO, тогда он будет fork()
(создаст собственную копию). Это создаст новый дочерний процесс. Этот новый сгенерированный дочерний процесс будет close()
его стандартным дескриптором выходного файла (fd 1) и привязать fd 1 к стороне записи канала, созданного процессом отцов (оболочка, в которой вы выполнили команду). Это возможно, потому что syscall fork()
будет поддерживать для каждого действительный открытый файловый дескриптор (в этом случае fd). После этого будет exec()
первая (в вашем случае) команда ps
, найденная в вашей переменной среды PATH
. При вызове exec()
процесс станет выполняемой вами командой.
Итак, теперь у вас есть процесс оболочки с дочерним элементом, который в вашем случае является командой ps
с атрибутами -ef
.
В этот момент отец (оболочка) fork()
снова. Этот вновь сгенерированный дочерний процесс close()
представляет собой стандартный дескриптор входного файла (fd 0) и прикрепляет fd 0 к стороне чтения канала, созданного процессом отцов (оболочка, в которой вы выполнили команду).
После этого будет exec()
первая (в вашем случае) grep
команда, найденная в вашей переменной среды PATH.
Теперь у вас есть процесс оболочки с двумя дочерними элементами (которые являются братьями и сестрами), где первая - это команда ps
с атрибутами -ef
, а вторая - это команда grep
с атрибутом cron
. Сторона считывания трубы присоединена к команде STDIN
команды grep
, а сторона записи присоединена к STDOUT
команды ps
: стандартный вывод команды ps
подключен к стандартный ввод команды grep
.
Так как ps
записывается для отправки стандартной информации вывода в каждом запущенном процессе, в то время как grep записывается, чтобы получить на своем стандартном входе то, что должно соответствовать заданному шаблону, вы получите ответ на свой первый вопрос
- выполняется оболочка:
ps -ef;
- выполняется оболочка:
grep cron;
-
ps
отправляет данные (которые даже содержат строку "grep cron" ) на grep
-
grep
соответствует шаблону поиска из STDIN
и соответствует строке "grep cron" из-за атрибута "cron", который вы передали в grep
: вы инструктируете grep
для соответствия "cron", и это происходит потому, что "grep cron" является строкой, возвращаемой ps
в то время, когда grep
запустил ее выполнение.
При выполнении:
ps -ef | grep '[c]ron'
переданный атрибут указывает grep
на соответствие тому, что содержит "c" , за которым следует "ron". Как и в первом примере, но в этом случае он сломает строку соответствия, возвращаемую ps
, потому что:
- выполняется оболочка:
ps -ef;
- оболочка работает:
rep [c]ron;
-
ps
отправляет данные (которые даже содержат строку grep [c]ron
) в grep
-
grep
не соответствует его шаблону поиска из stdin, потому что строка, содержащая "c" , за которой следует "ron", она не найдена, но она обнаружила строку, содержащую "c" , за которой следует "] ron"
GNU grep
не имеет ограничений на соответствие строк, а на некоторых платформах (я думаю, Solaris, HPUX, aix) предел строки задается переменной "$ COLUMN" или шириной экрана терминала.
Надеюсь, этот длинный ответ немного пояснит процесс оболочки.
Совет:
ps -ef | grep cron | grep -v grep
Ответ 2
В вашей команде
ps -ef | grep 'cron'
Linux выполняет команду grep перед командой ps -ef. Затем Linux сопоставляет стандартный вывод (STDOUT) "ps -ef" со стандартным входом (STDIN) команды grep.
Он не выполняет команду ps, сохраняет результат в памяти и передает ее в grep. Подумайте об этом, почему? Представьте себе, если бы вы собирали сотни гигабайт данных?
Изменить В отношении вашего второго вопроса:
В grep (и большинстве движков регулярных выражений) вы можете указать скобки, чтобы они знали, что вы примете ЛЮБОЙ символ в скобках. Поэтому запись [c] означает, что он примет любой charcter, но указывается только 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 содержит c, а затем "ron". Это не соответствует вашему запросу, потому что ваш запрос [c] ron
Вы можете поместить все, что хотите, в скобки, если оно содержит c:
ps aux | grep [cbcdefadq]ron
root 1079 0.0 0.0 18976 1032 ? Ss Mar08 0:00 cron
Если вы удалите C, это не будет соответствовать, потому что "cron" начинается с c:
ps aux | grep [abedf]ron
^ Не имеет результатов
Изменить 2
Чтобы повторить этот момент, вы можете делать всевозможные сумасшедшие вещи с помощью grep. Нет никакого смысла в выборе первого символа, чтобы сделать это с.
ps aux | grep [c][ro][ro][n]
root 1079 0.0 0.0 18976 1032 ? Ss Mar08 0:00 cron
Ответ 3
Оболочка конструирует ваш конвейер с помощью цепочек вызовов fork()
, pipe()
и exec()
. В зависимости от оболочки любая ее часть может быть построена первой. Так что grep
может быть запущен до начала ps
. Или, даже если сначала начинается ps
, он будет записывать в буфер ядра ядра 4k и в конечном итоге будет блокировать (при печати строки вывода процесса) до тех пор, пока grep
не запустится и не начнет потреблять данные в трубе. В последнем случае, если ps
может начать и закончить до начала grep
, вы можете не увидеть grep cron
на выходе. Возможно, вы уже заметили, что этот детерминизм уже играет.
Ответ 4
На ваш вопрос был дан ответ другими, но я предлагаю совет: если вы хотите избежать просмотра процесса grep
, вы можете сделать это следующим образом:
$ ps -ef | grep [c]ron
Ответ 5
Вы писали: "С моей точки зрения, ps перечисляет процессы и пересылает список в grep. grep даже не запускался, а ps перечисляет процессы".
Ваше понимание неверно.
Это не работает трубопровод. Оболочка не запускает первую команду для завершения, запоминает вывод первой команды, а затем запускает следующую команду, используя эти данные в качестве входных данных. Нет. Вместо этого оба процесса выполняются, и их входы/выходы подключены. Как писал Бен Джексон, нет ничего особого, чтобы гарантировать, что процессы будут работать в одно и то же время, если они оба очень недолговечны, и если ядро может с комфортом управлять небольшим количеством данных, проходящих через соединение. В этом случае это действительно может произойти так, как вы ожидаете, только случайно. Но концептуальная модель должна иметь в виду, что они работают параллельно.
Если вы хотите использовать официальные источники, как насчет страницы bash man:
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 окажется в списке процессов, а вторая не будет.
Ответ 6
$ ps -ef | grep cron
Linux Shell всегда выполняет команду справа налево. поэтому перед выполнением ps -ef grep cron уже выполнил то, почему o/p показывает команду.
$ ps -ef | grep [c]ron
Но в этом u указан grep ron, за которым следует только c. поэтому o/p не имеет командной строки, потому что в команде есть [c] ron.
Ответ 7
pgrep
иногда лучше, чем ps -ef | grep word
, потому что он исключает grep
. Попробуйте
pgrep -f bash
pgrep -lf bash