Почему ls
требуется отдельный процесс для его выполнения? Я знаю причину, по которой команды наподобие cd
не могут быть выполнены механизмом разветвления, но есть ли вред, если они ls
выполняются без разветвления?
Почему ls
требуется отдельный процесс для его выполнения? Я знаю причину, по которой команды наподобие cd
не могут быть выполнены механизмом разветвления, но есть ли вред, если они ls
выполняются без разветвления?
Ответы:
Ответ более или менее ls
- внешний исполняемый файл. Вы можете увидеть его местоположение, запустив type -p ls
.
Почему тогда не ls
встроен в оболочку? Ну почему так должно быть? Задача оболочки состоит не в том, чтобы охватить все доступные команды, а в том, чтобы обеспечить среду, способную их выполнять. У некоторых современных оболочек есть echo
, printf
и их аналог как встроенные, которые технически не обязательно должны быть встроенными, но сделаны из соображений производительности, когда они запускаются многократно (в основном в тесных циклах). Не делая их встроенными, оболочка должна была бы форкать и выполнять новый процесс для каждого вызова к ним, который может быть очень медленным.
По крайней мере, запуск ls
внешнего исполняемого файла требует выполнения одного из системных вызовов семейства exec. Вы можете сделать это без разветвления, но это заменит основную оболочку, которую вы используете. Вы можете увидеть, что происходит в этом случае, выполнив следующие действия:
exec ls; echo "this never gets printed"
Поскольку образ процесса вашей оболочки заменен, текущая оболочка больше не доступна после этого. Чтобы оболочка могла продолжать работать после запуска ls, команда должна быть встроена в оболочку.
Форкинг позволяет заменить процесс, который не является вашей основной оболочкой, что означает, что вы можете продолжить запускать свою оболочку впоследствии.
echo
, printf
и т.д.
cd
не внешний исполняемый файл?
В Bash Reference Manual гласит:
Встроенные команды необходимы для реализации функциональности, которую невозможно или неудобно получить с помощью отдельных утилит.
То есть оболочки предназначены для включения только встроенных команд, если:
Команда ls
не соответствует ни одному из вышеуказанных требований.
Однако здесь нет программных ограничений, которые бы препятствовали ls
внедрению в качестве встроенного, который выполняется в том же процессе, что и интерпретатор bash. Причины, по которым команды не внедряются в состав встроенных командных оболочек:
Что касается первой причины - вы хотите, чтобы оболочка была как можно более независимой и устойчивой. Вы не хотите, чтобы оболочка зависала ls
при монтировании NFS, которое «не отвечает, все еще пытается».
Что касается второй причины - во многих случаях вы можете использовать оболочку для системы, которая использует Busybox или другую файловую систему, которая имеет другую ls
реализацию. Или даже использовать один и тот же источник оболочки в ОС, которые имеют разные ls
реализации.
Что касается третьей причины - для таких выражений find . -type d | xargs ls -lad
было бы трудно или невозможно реализовать их ls
в том же процессе, что и интерпретатор оболочки.
Что касается четвертой причины - выполнение некоторых ls
команд может занять много времени. Возможно, вы захотите, чтобы оболочка продолжала делать что-то еще в это время.
Примечание: Смотрите этот полезный пост по Уоррен Янг в ответ на подобный вопрос.
ls
во внешний процесс. Это может быть сделано, но это будет сложно.
bash
вывод alias | grep ls
. входcat /etc/passwd | while read a; do echo "$a"; done
ls
не требует отдельного процесса. Очень немногие команды фактически требуют отдельного процесса: только те, которые должны изменить привилегии.
Как правило, оболочки реализуют команды как встроенные, только когда эти команды должны быть реализованы как встроенные. Команды , как alias
, cd
, exit
, export
, jobs
, ... нужно прочитать или изменить некоторое внутреннее состояние оболочки, и , следовательно , не могут быть отдельные программы. Команды, которые не имеют таких требований, могут быть отдельными командами; таким образом, они могут быть вызваны из любой оболочки или другой программы.
Глядя на список встроенных команд в bash, только следующие встроенные функции могут быть реализованы в виде отдельных команд. Для некоторых из них возможна небольшая потеря функциональности.
command
- но он потеряет свою полезность в ситуациях, когда он PATH
может быть неправильно настроен, и сценарий используется command
как часть его настройки.echo
- это встроенный для эффективности.help
- он может использовать отдельную базу данных, но встраивание текста справки в исполняемый файл оболочки имеет то преимущество, что делает исполняемый файл оболочки автономным.kill
- наличие встроенной функции имеет два преимущества: она может распознавать обозначения заданий в дополнение к идентификаторам процессов и может использоваться даже тогда, когда не хватает ресурсов для запуска отдельного процесса.printf
- по той же причине echo
, что и для поддержки -v
возможности помещения вывода в переменную.pwd
- встроенная функция предоставляет дополнительную возможность логического отслеживания текущего каталога (оставляя символические ссылки без изменений, а не расширяя их).test
- это встроенная система для повышения эффективности (и bash также работает с файлами, вызываемыми /dev/fd/…
в некоторых операционных системах).Несколько оболочек предлагают значительное количество дополнительных встроенных элементов. Есть sash , представляющий собой оболочку, разработанную как отдельный двоичный файл для аварийного ремонта (когда некоторые внешние команды могут быть недоступны). Он имеет встроенный ls
, вызываемый -ls
, а также другие инструменты, такие как -grep
и -tar
. Встроенные Sash-возможности имеют меньше возможностей, чем полноценные команды. Zsh предлагает несколько подобных встроенных функций в своем модуле zsh / files . Он не имеет ls
, но подстановочный знак расширения ( echo *
) и zstat
может выполнять аналогичную функцию.
Я думаю, что здесь чего-то не хватает людям, это сложная программа GNU ls
на Linux. Сравнивая размер исполняемого файла ls
с оболочкой bash
and dash
в моей системе Debian, мы видим, что он довольно большой:
graeme@graeme:~$ ls -lh /bin/{ls,bash,dash}
-rwxr-xr-x 1 root root 953K Mar 30 2013 /bin/bash
-rwxr-xr-x 1 root root 115K Dec 25 20:25 /bin/dash
-rwxr-xr-x 1 root root 108K Jul 20 22:52 /bin/ls
Включение такой ls
же полнофункциональной версии, как в версии GNU bash
, увеличит размер исполняемого файла на 10%. Это почти такой же размер, как полная dash
оболочка!
Большинство встроенных команд оболочки выбраны потому, что они интегрируются с оболочкой таким образом, что внешние исполняемые файлы не могут (вопрос указывает на это cd
, но другой пример - это версия kill
интеграции bash с управлением заданиями bash) или потому, что они представляют собой очень простые для реализации команды, давая большую скорость против размера выплаты ( true
и false
примерно так же просто, как он получает).
У GNU ls
был длинный цикл разработки, и он может реализовывать различные опции для настройки того, какие / как результаты отображаются. Использование встроенных ls по умолчанию либо потеряло бы эту функциональность, либо значительно увеличило бы сложность и размер оболочки.
Это сделать то, что вы ищете:
printf "%s\n" *
Также вы можете хранить имена файлов в массиве:
files=(`printf "%s\n" *`) #items are separated by whitespace
echo ${#files[*]} files
for index in ${!a[*]}
do printf "%d: %s\n" $index ${a[$index]};
done
Но он не заботится о пробелах в именах.
Он переходит к переменной и заботится о пробелах:
printf "%s\n" * | while read a; do echo $a; done
ls
это внешняя программаecho *
илиecho * .*
(в зависимости от параметров оболочки) довольно неплохо выполняет распечатку файлов без разветвления.