Почему «ls» требует отдельного процесса для выполнения?

14

Почему lsтребуется отдельный процесс для его выполнения? Я знаю причину, по которой команды наподобие cdне могут быть выполнены механизмом разветвления, но есть ли вред, если они lsвыполняются без разветвления?

crisron
источник
1
Хотя lsэто внешняя программа echo *или echo * .*(в зависимости от параметров оболочки) довольно неплохо выполняет распечатку файлов без разветвления.
Gerrit
Это даже лучше: printf "% s \ n" *
Costa
Примечание разнообразия оболочки: tcsh имеет встроенную функцию, ls-Fкоторая действует как ls -F. Это для эффективности. Вы всегда получаете -Fчто обычно хорошая идея. Если вы укажете какие-либо другие параметры, они будут добавлены к внешней команде.

Ответы:

18

Ответ более или менее ls- внешний исполняемый файл. Вы можете увидеть его местоположение, запустив type -p ls.

Почему тогда не lsвстроен в оболочку? Ну почему так должно быть? Задача оболочки состоит не в том, чтобы охватить все доступные команды, а в том, чтобы обеспечить среду, способную их выполнять. У некоторых современных оболочек есть echo, printfи их аналог как встроенные, которые технически не обязательно должны быть встроенными, но сделаны из соображений производительности, когда они запускаются многократно (в основном в тесных циклах). Не делая их встроенными, оболочка должна была бы форкать и выполнять новый процесс для каждого вызова к ним, который может быть очень медленным.

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

exec ls; echo "this never gets printed"

Поскольку образ процесса вашей оболочки заменен, текущая оболочка больше не доступна после этого. Чтобы оболочка могла продолжать работать после запуска ls, команда должна быть встроена в оболочку.

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

Крис Даун
источник
1
Я думаю, он спрашивает, почему ls (1) не является встроенной функцией оболочек, и кто-то должен объяснить, как разные поставщики имеют разные опции для ls (1) и могут запрашивать разные вещи из файловой системы и т. Д. А также взлеты и, в основном, недостатки того, что он «встроен» в оболочку.
Луа
@llua я добавил некоторую информацию о том , что и случаи исключения из echo, printfи т.д.
Крис Даун
Не всегда понятно, почему одни вещи встроены, а другие нет. Например, почему cdне внешний исполняемый файл?
Фахим Митха
@FaheemMitha В POSIX-совместимых операционных системах есть внешний cdисполняемый файл ( см. Здесь ). Если вы хотите использовать chdir () в текущем процессе, вам нужно встроить его в оболочку.
Крис Даун
это стало привычкой, почему lsона внешняя, но она также может быть реализована в оболочке. Смотрите busybox.
15

В Bash Reference Manual гласит:

Встроенные команды необходимы для реализации функциональности, которую невозможно или неудобно получить с помощью отдельных утилит.

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

  1. Требуется стандартом POSIX
  2. Команды, которые требуют доступа к самой оболочке, такие как встроенные средства управления заданиями
  3. Очень простые команды, не зависящие от ОС и повышающие эффективность выполнения при реализации в виде встроенных компонентов, таких как printf

Команда lsне соответствует ни одному из вышеуказанных требований.

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

  1. Оболочка должна быть отделена от файловой системы - никакие встроенные команды не должны зависеть от правильной работы любой файловой системы или периферийных устройств.
  2. Команда, которая может быть типом файловой системы или операционной системой, должна быть отдельным исполняемым файлом
  3. Команда, к которой вы, возможно, захотите передать по конвейеру, должна быть отдельным процессом
  4. Команда, которую вы можете запустить в фоновом режиме, должна быть отдельным исполняемым файлом
  5. Команда с большим количеством возможных параметров лучше реализована в отдельном исполняемом файле.
  6. Команды, которые должны иметь одинаковый вывод, независимо от того, какой тип оболочки (bash, csh, tsh, ...) их вызывает, должны быть автономными исполняемыми файлами

Что касается первой причины - вы хотите, чтобы оболочка была как можно более независимой и устойчивой. Вы не хотите, чтобы оболочка зависала lsпри монтировании NFS, которое «не отвечает, все еще пытается».

Что касается второй причины - во многих случаях вы можете использовать оболочку для системы, которая использует Busybox или другую файловую систему, которая имеет другую lsреализацию. Или даже использовать один и тот же источник оболочки в ОС, которые имеют разные lsреализации.

Что касается третьей причины - для таких выражений find . -type d | xargs ls -ladбыло бы трудно или невозможно реализовать их lsв том же процессе, что и интерпретатор оболочки.

Что касается четвертой причины - выполнение некоторых lsкоманд может занять много времени. Возможно, вы захотите, чтобы оболочка продолжала делать что-то еще в это время.


Примечание: Смотрите этот полезный пост по Уоррен Янг в ответ на подобный вопрос.

Джонатан Бен-Авраам
источник
Вы упустили простоту конвейерного вывода, если это отдельная команда, и все программирование, которое потребовалось бы для передачи примитива оболочки в отдельный исполняемый файл.
Брюс Эдигер
@BruceEdiger: Как приятно получить комментарий от уважаемого BE. Благодарность! Я считаю, что причина 3 охватывает ваш комментарий, нет?
Джонатан Бен-Авраам
1
Я думал о том, насколько сложным будет исходный код самой оболочки, если он должен обрабатывать каналы для внешних процессов и направлять вывод внутренней команды, такой как гипотетическая, lsво внешний процесс. Это может быть сделано, но это будет сложно.
Брюс Эдигер
1
Боюсь, что большинство, если не все ваши 5 баллов, являются спорными. 1: ls (надеюсь) не зависит от реализации файловой системы. Это зависит от ядра, чтобы обеспечить согласованный интерфейс со стандартной библиотекой и приложениями. 2: ls, вероятно, меньше зависит от ОС, чем оболочка. 3: оболочки определенно позволяют встроить в конвейеры. 4: оболочки определенно позволяют встроенным функциям работать в фоновом режиме. 5: это довольно субъективно.
Jlliagre
1
@ JonathanBen-Avraham @BruceEdiger Разве оболочка уже не обрабатывает трубу для встроенных объектов с подоболочками? например, bashвывод alias | grep ls. входcat /etc/passwd | while read a; do echo "$a"; done
Мэтт
2

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может выполнять аналогичную функцию.

Жиль "ТАК - перестань быть злым"
источник
2

Я думаю, что здесь чего-то не хватает людям, это сложная программа GNU lsна Linux. Сравнивая размер исполняемого файла lsс оболочкой bashand 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 по умолчанию либо потеряло бы эту функциональность, либо значительно увеличило бы сложность и размер оболочки.

Graeme
источник
1

cdвстроен в оболочку, lsэто отдельная программа, которую вы увидите /bin/ls.

DopeGhoti
источник
0

Это сделать то, что вы ищете:

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
ребро
источник