Я никогда не задумывался о том, как на самом деле оболочка выполняет конвейерные команды. Я всегда говорили , что «стандартный вывод одной программы получает по трубопроводу в потоке ввод других,» как способ мышления о трубах. Естественно, я подумал, что в случае, скажем, A | B, A запускается первым, затем B получает стандартный вывод A и использует стандартный вывод A в качестве входных данных.
Но я заметил, что когда люди ищут определенный процесс в ps, они включают grep -v "grep" в конце команды, чтобы убедиться, что grep не появляется в конечном выводе. Это означает, что в команде ps aux | grep "bash" | grep -v "grep", что означает, что ps знал, что grep запущен и поэтому находится в выводе ps. Но если ps завершает работу до того, как его выходные данные будут переданы в grep, как он узнал, что grep работает?
flamingtoast@FTOAST-UBUNTU: ~$ ps | grep ".*"
PID TTY TIME CMD
3773 pts/0 00:00:00 bash
3784 pts/0 00:00:00 ps
3785 pts/0 00:00:00 grep
Ответы:
Команды по конвейеру выполняются одновременно. Когда вы запускаете
ps | grep …
, это удача ничьей (или вопрос деталей работы оболочки в сочетании с тонкой настройкой планировщика глубоко в недрах ядра) относительно того, начинается ли сначалаps
илиgrep
начинается, и в любом случае они продолжают выполнить одновременно.Это очень часто используется для того, чтобы вторая программа могла обрабатывать данные, полученные из первой программы, до того, как первая программа завершила свою работу. Например
начинает отображать совпадающие строки в верхнем регистре еще до того,
grep
как закончил обход большого файла.отображает первую совпадающую строку и может прекратить обработку задолго до того,
grep
как закончит чтение своего входного файла.Если вы где-то читали, что программы по конвейеру запускаются последовательно, бегите от этого документа. Канальные программы запускаются одновременно и всегда работают.
источник
grep
программы, и есть буфер под управлением ядра в самой трубе. Для последнего, посмотрите, Насколько велика труба буфера?Порядок выполнения команд на самом деле не имеет значения и не гарантируется. Оставив в стороне тайных детали
pipe()
,fork()
,dup()
иexecve()
, оболочка сначала создает трубу, трубопровод для данных , которые будут течь между процессами, а затем создает процессы с концами трубы , соединенной с ними. Первый запущенный процесс может блокировать ожидание ввода от второго процесса или блокировать ожидание, пока второй процесс начнет читать данные из канала. Эти ожидания могут быть сколь угодно длинными и не имеют значения. Независимо от порядка запуска процессов, данные в конечном итоге передаются, и все работает.источник
Риск избиения мертвой лошади, кажется, ошибочное мнение, что
эквивалентно
Но, когда Unix был создан, и дети ездили с динозаврами в школу, диски были очень маленькими, и довольно обычная команда использовала все свободное пространство в файловой системе. Если бы
B
что-то было похоже , конечный результат конвейера мог бы быть намного меньше, чем этот промежуточный файл. Таким образом, канал был разработан не как сокращение для модели « сначала запустить A , а затем запустить B с вводом из выходных данных A », а как способ одновременного выполнения и устранения необходимости сохранения промежуточного файла. на диске.grep some_very_obscure_string
B
A
источник
Обычно вы запускаете это под Bash. процесс работает и запускается одновременно, но выполняется оболочкой параллельно. Как это возможно?
Система не гарантирует, насколько быстро будет выполняться exec, и запускается указанная команда. это не зависит от оболочки, но система. Это потому что:
один раз показать
grep
и / илиps
команду, а теперь следующий. Это зависит от того, насколько быстро ядро действительно запускает процессы, используя функцию exec системы.источник
exec()
выполняется, но как чередуютсяexec()
вызовы и выполнение программ в конвейере .