Имеет ли оболочка тот же стандартный ввод, стандартный вывод, стандартную ошибку, что и каждая другая команда?

Имеет ли оболочка тот же стандартный ввод, стандартный вывод, стандартную ошибку, что и каждая другая команда?

Например, bash находится в /bin/bash, это означает, что это команда, а каждая команда имеет три (0,1,2) поры: стандартный ввод, стандартный вывод, стандартная ошибка.

Верно ли это на 100 процентов и для оболочки, или есть что-то иное, учитывая особое значение оболочки как команды или процесса?

решение1

Это то же самое, что и любая другая программа. Это позволяет вам перенаправлять и перенаправлять ввод-вывод, как и другие программы.

echo "cat filename" | bash

выполнит cat filenameкоманду при bashчтении стандартного ввода из канала.

bash -c "echo foo" > filename

выполнит echo fooкоманду, а вывод будет перенаправлен в файл.

В Unix в оболочке нет ничего "особенного". Это просто обычная программа, чьей основной целью является выполнение других программ.

решение2

Давайте разберемся в терминологии:

Акомандаэто то, что вы вводите в свою оболочку. Это может бытьпсевдонимилифункция оболочки, или это может относиться кзапускаемый файл.

Анзапускаемый файлможет бытьдвоичный исполняемый файл(т.е. тот, который содержит непосредственно машинный код) илисценарий. Скрипты включают в себя скрипты bash, скрипты sh, скрипты perl, скрипты awk, скрипты sed, скрипты python и т. д.

Первые два байта вашего скрипта (если он должен быть выполнен непосредственно как исполняемый файл) должны быть #!, что является «магическим числом», которое сигнализирует вашему ядру о необходимости считывать дополнительные байты, пока не будет прочитана новая строка, интерпретируйте эти байты как путь кдвоичный исполняемый файл, возможно с одним аргументом, разделенным пробелом (например #!/bin/awk -f), и выполнитьчтодвоичный исполняемый файл, в котором в качестве аргумента передается путь к самому скрипту.

В конечном счете, единственное, что ядро ​​может реально выполнить, это машинный код, т. е. двоичный исполняемый файл. Двоичные исполняемые файлы, такие как sh, bash, perl, python, awk и т. д. называютсяпереводчики. Они интерпретируют сценарий и выполняют его инструкции. Но для выполнения они сами должны существовать в машинном коде.

Когда программа (двоичный исполняемый файл) фактически запускается ядром, она существует какпроцесс. Двоичный исполняемый файл — это просто файл, содержащий инструкции.процесспредставляет собой «запущенный экземпляр программы»; точнее, это абстракция, встроенная в ядро, имеющая связанную с ним память, переменные среды, идентификатор процесса (PID),дескрипторы файловкоторые он может использовать для ввода и вывода, и других атрибутов. Вы можете запустить исполняемый файл более одного раза «одновременно» (не буквально одновременно на одноядерной машине, но из-за того, как ядро ​​выделяет циклы ЦП, он будетказатьсяодновременно) и каждый запущенный экземпляр будет отдельным процессом, даже если все они являются экземплярами одной и той же программы.

0, 1 и 2 — стандартный ввод, стандартный вывод и стандартная ошибка — являютсядескрипторы файлов. По правде говоря, они вообще существуют только по соглашению. Вы можете создать программу на языке C, которая будет запускать (выполнять) другие программы (исполнять различные двоичные исполняемые файлы), вообще не предоставляя им эти файловые дескрипторы. Однако,Поскольку все стандартные программы написаны с учетом доступности файловых дескрипторов 0, 1 и 2, вы, скорее всего, не получите ничего, кроме ошибок (в большинстве случаев), и программы не будут работать правильно.

Чтобы действительно полностью это понять, вы должны понятькак возникает процесс. Это немного похоже на чудо рождения. ;) Все процессы должны быть запущеныдругойпроцесс. Не беспокоясь о том, как запускается первый процесс при загрузке системы, процесс с PID 1 называется «init» и запускает другие основные процессы, необходимые вашей операционной системе для функционирования.

Процесс запуска другого процесса состоит из двух основных этапов:вилкаиисп. Оба они являются системными вызовами, то есть действиями/запросами, которые отправляет процесс.к ядрукоторые фактически может выполнить только ядро.

«Fork» означает (в двух словах) «ядро, пожалуйста, сделай копию меня». («Я» — это запущенный процесс.) Ядро делает полную копию процесса — его файловые дескрипторы, память, состояние выполнения (где оно находится в соответствии с инструкциями, которые составляют программу, экземпляром которой оно является), переменные окружения и т. д. Так что это «клон» процесса. Теперь как вы можете отличить оригинал от копии? Только по одному: по статусу возврата системного forkвызова. Дочерний процесс получает «0» (успех), а родительский процесс получает PID недавно созданного дочернего процесса. Таким образом, проверяя этот статус возврата, каждый процесс может выяснить, что ему следует делать сейчас (потому что помните, они следуют одному и тому же набору инструкций!).

"Exec" на самом деле "execve()". В двух словах, он просит ядро: "ядро, пожалуйстазаменятьменя (я процесс) с экземпляром программы, указанной в ______ файле." И программист также указываетаргументычто новый процесс будет иметь, исреда(массив переменных среды), которые он будет иметь.

Итак, когда вы вводите команду в оболочку, на самом деле (в большинстве случаев, игнорируя особые случаи, такие как встроенные команды оболочки, например cd) происходит следующее: ваша оболочка (которая является запущенным процессом)вилки,а потомруководителиуказанная вами команда.

Если вы выполнили перенаправление вывода или ввода, например /bin/echo hello > /dev/null, то ответвленный дочерний процессперед execэхомсоответствующим образом скорректирует свои файловые дескрипторы, так что файловый дескриптор 1 (в этом примере) будет привязан к /dev/nullвашему терминалу или к тому месту, где он был раньше.

Итак, да, любой запущенный экземпляр исполняемого файла /bin/bashбудет ожидать наличия файлового дескриптора 0, из которого он может считывать входные данные, файлового дескриптора 1, в который он может записывать выходные данные, и файлового дескриптора 2, в который он может считывать и записывать сообщения об ошибках и аналогичные входные/выходные данные.

Связанный контент