Почему обязательные утилиты POSIX не встроены в оболочку?

45

Цель этого вопроса - ответить на любопытство, а не решить конкретную вычислительную проблему. Вопрос заключается в следующем: почему обязательные утилиты POSIX обычно не встроены в реализации оболочки?

Например, у меня есть сценарий, который в основном считывает несколько небольших текстовых файлов и проверяет, правильно ли они отформатированы, но для запуска на моем компьютере требуется 27 секунд из-за значительного количества операций со строками. Эта строковая манипуляция создает тысячи новых процессов, вызывая различные утилиты, отсюда и медлительность. Я довольно уверен , что если некоторые утилиты были построены, а именно grep, sed, cut, tr, и expr, то скрипт будет работать в секунду или меньше ( на основе моего опыта в C).

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

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

рукав моря
источник
15
Если 27 секунд слишком медленные, вы можете использовать Python, Perl или другой полукомпилированный язык. Или опубликуйте медленные части вашего скрипта и попросите улучшения. Возможно, вы используете три или четыре команды, которые может выполнять одна (более быстрая).
Ройма
8
К сожалению, оболочки не были созданы для тяжелых задач, и, к сожалению, мир сильно изменился с тех пор, как вы могли использовать только сценарий оболочки. Я согласен с roaima - каждый разумный сисадмин должен идти на Python или Perl и не ожидать, что оболочка справится со всем
Сергей Колодяжный
16
Основное назначение оболочки - запускать другие программы, а не манипулировать данными напрямую. За прошедшие годы некоторые внешние программы или функции, предоставляемые ими (глобализация, арифметика printfи т. Д.), Были включены в оболочки, когда они считались достаточно полезными.
chepner
8
Если вы опубликуете свой скрипт на codereview.stackexchange.com, я уверен, что рецензенты могли бы внести некоторые предложения, чтобы значительно ускорить ваш скрипт (или, по крайней мере, указать, почему он должен быть написан на Python / etc вместо оболочки).
chepner
5
@Kyle: awkобязательная утилита в POSIX, и особенно хорошо подходит (то есть, очень быстро) для реализации сценариев , которые вы могли бы реализовать с помощью sed, cut, tr, grepи exprв сценарии оболочки.
Номинальное животное

Ответы:

11

Сценарии оболочки не должны работать с такой скоростью. Если вы хотите улучшить скорость вашего скрипта, попробуйте его на Perl. Если это все еще слишком медленно, вам придется перейти на статически типизированный язык, такой как java или c, или написать модуль C для perl, который запускает слишком медленные части.

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

Ожидается, что ОС Unix будет включать в себя множество небольших программ, которые выполняют четко определенные задачи, составляющие большую картину. Это хорошая вещь, поскольку она разделяет большие программы. Взгляните, например, на qmail и сравните это с sendmail. qmail состоит из многих программ:

http://www.nrg4u.com/qmail/the-big-qmail-picture-103-p1.gif

Использование сетевого демона не поможет вам использовать диспетчер очереди.

Эд Невилл
источник
ОП специально НЕ просил предложений по улучшению скорости кода. Вопрос заключался в том, почему некоторые утилиты не являются встроенными, как cdили pwd.
Стивен C
4
Правда. Ответ состоял в том, чтобы выразить разницу между монолитным и разделенным на части и показать причину в этой пользу.
Эд Невилл
Связанный: askubuntu.com/a/291926/11751
CVn
1
@StephenC cdявляется встроенным - и это действительно должно быть, потому что изменение рабочего каталога в подпроцессе не влияет на родительские процессы.
Йонас
67

Почему обязательные утилиты POSIX не встроены в оболочку?

Поскольку для совместимости с POSIX требуется, чтобы система 1 предоставляла большинство утилит в качестве автономных команд.

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

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

Обратите внимание, что по крайней мере ksh93, bashи zshидти дальше, предоставляя пользовательские методы для запуска оболочки для динамической загрузки встроенных из общих библиотек. Технически ничто тогда не мешает всем утилитам POSIX быть реализованными и доступными как встроенные.

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

1 POSIX.1-2008

Однако все стандартные утилиты , включая обычные встроенные в таблицу, но не специальные встроенные утилиты, описанные в специальных встроенных утилитах, должны быть реализованы таким образом, чтобы к ним можно было получить доступ через семейство exec функции, определенные в томе «Системные интерфейсы» в POSIX.1-2008, и могут вызываться непосредственно теми стандартными утилитами, которым это требуется (env, find, nice, nohup, time, xargs).

jlliagre
источник
4
Это правильный ответ, но я бы просто добавил, что, поскольку интерфейс этих утилит, как правило, через stdin / stdout, в любом случае, что даже если бы каждая из них была также реализована как встроенная подпрограмма в bash, она все равно будет эффективно раскошелиться себя и создавать трубы для каждой команды в трубопроводе в любом случае, так что будет только маргинальные прибыль
Chunko
2
@ Чунько Да. хотя подоболочки легче, чем процессы fork / exec.
jlliagre
3
@slebetman Вы упускаете мою точку зрения. Подоболочки не являются ни потоками, ни исполняемыми процессами, независимо от того, работают они в Linux или нет. Субоболочки - это просто клон их родителей, созданный, за которым fork не следует exec; forkв настоящее время очень легкая операция по сравнению с exec.
jlliagre
3
Я измерил noforkвстроенные функции busybox как на 10 раз меньше служебных данных, чем noexecвстроенные, которые, в свою очередь, имели на ~ 5 раз меньше служебных данных, чем fork + exec отдельного двоичного файла. Определения в соответствии с unix.stackexchange.com/a/274322/29483 Интересно, что busybox не noforkвсе, хотя я знаю, что некоторый код busybox сокращается из-за не очистки памяти, а просто полагается на кратковременный процесс.
sourcejedi
1
@jlliagre: В Linux форк создает процесс. Возможно, вы упускаете из виду то, что в Linux они настолько оптимизировали процессы, что разработчики решили, что больше нет никакого преимущества в создании чего-то более легкого. В основном в Linux процесс так же легок, как поток.
Slebetman
9

Из справочного руководства BASH ,

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

Как я уверен, вы слышали, философия UNIX в значительной степени опирается на несколько приложений, которые имеют ограниченную функциональность. У каждого встроенного есть очень веская причина, почему оно встроено. Все остальное - нет. Я думаю, что более интересный класс вопросов вдоль линий, «почему именно это pwd встроенный?»

Стивен С
источник
2
Одним словом: модульность
Пешке
2
/ bin / pwd существует. Я думаю, cdчто был бы лучшим примером здесь чего-то, что невозможно реализовать в качестве отдельного инструмента.
Оскар Ског
1
@OskarSkog Это было главное. cdдолжен быть встроен, pwdнет. Так почему же bashразработчики решили включить его?
Стиг Хеммер
1
... на который распространяется unix.stackexchange.com/questions/145479 .
JdeBP
@StigHemmer /bin/bashсуществует, но он все еще встроен. См. Список встроенных функций по адресу gnu.org/software/bash/manual/html_node/…
Стивен С.
8

Ребята из AT & T задали себе то же самое

Если вы посмотрите на историю AT & T Software Toolkit (в настоящее время бездействующей на github с тех пор, как основная команда ушла), то это именно то, что они сделали с оболочкой AT & T Korn, также известной как ksh93.

Производительность всегда была частью мотивации сопровождающих ksh93, и при сборке ksh вы можете выбрать создание многих распространенных утилит POSIX в качестве динамически загружаемых библиотек. Привязывая эти команды к имени каталога, например /opt/ast/bin, вы можете контролировать, какая версия команды будет использоваться, основываясь на положении этого имени каталога в $PATH.

Примеры:

cat chmod chown cksum cmp cp cut date expr fmt head join ln
mkdir mkfifo mktemp mv nl od paste rm tail tr uniq uuencode wc

Полный список можно найти в репозитории github ast .

Обратите внимание, что большинство инструментов ast имеют свое происхождение и будут сильно отличаться от более распространенных реализаций gnu. Исследовательская команда AT & T придерживалась официальных стандартов, что было способом достижения совместимости, когда вы не могли делиться кодом.

Хенк Лангевельд
источник
6

Таким образом, мы не использовали ресурсы для оптимизации оригинального инструмента, чтобы удовлетворить каждое конкретное желание. Я думаю, что нам нужно объяснить, сколько стоило бы реализовать это конкретное желание.

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

это плохое предположение :-P.

Системы Post-POSIX продолжают становиться более мощными и удобными по веским причинам; в качестве стандартного факта он никогда не догоняет.

Ubuntu начала попытки перейти на упрощенную POSIX-оболочку для сценариев, чтобы оптимизировать старый процесс загрузки System V init. Я не говорю, что это не помогло, но это действительно вызвало много ошибок, которые нужно было устранить: «ошибки», скрипты, которые выполнялись /bin/sh, предполагая, что bashфункции были доступны.

POSIX sh не является хорошим языком программирования общего назначения. Его основная цель - хорошо работать как интерактивная оболочка. Как только вы начнете сохранять свои команды в сценарии, имейте в виду, что вы приближаетесь к тарпиту Тьюринга . Например, невозможно обнаружить сбои в середине обычного конвейера . bashдобавлено set -o pipefailдля этого, но это не в POSIX.

Подобные полезные, но нестандартные функции предоставляются почти каждой более сложной утилитой, чем true.

Для класса задачи, который вы наметите, вы можете нарисовать грубую линию для Awk, Perl и современного Python. Различные инструменты были созданы и развивались независимо. Вы ожидаете, что, например, GNU Awk будет включен в расширенный libutilposix?

Я не говорю, что у нас теперь есть один универсально лучший подход, на который я могу вам указать. У меня есть слабость к Python. Awk на удивление мощен, хотя меня разочаровали некоторые особенности, специфичные для GNU Awk. Но дело в том, что обработка большого количества строк по отдельности (предположительно из строк файлов) не была целью разработки оболочки POSIX.

sourcejedi
источник
Интересно, возникнут ли какие-либо трудности с оболочкой, которая предполагает, что любая команда, выполняемая из настраиваемого списка расположений, будет рассматриваться как встроенная в тех случаях, когда оболочка все понимает в этой команде? Если скрипт выполняет cat -@fnord fooоболочку, он должен решить, так как он не знает, что -@означает, что ему нужно будет вызвать фактическую команду, но, учитывая, что cat <foo >barоболочка не должна вызывать другой процесс.
суперкат
1
сложность @supercat.
sourcejedi
2

Существует также вопрос: в какую оболочку вы бы его встроили?

Большинство систем Unix / Linux имеют несколько различных оболочек, которые разрабатываются независимо (sh / bash / korn / ???). Если вы встраиваете инструменты в оболочку, вы получите разные реализации этих инструментов для каждой оболочки. Это может привести к накладным расходам, и вы можете столкнуться с различными функциями / ошибками, например, в grep, в зависимости от того, какую оболочку вы использовали для ее вызова.

MTilsted
источник
Zsh довольно популярен в некоторых кругах в эти дни. У csh / tcsh исторически было много поклонников, но я не думаю, что вы видите это сегодня. И есть целая пачка менее известных оболочек ...
CVn
Модульность. В случае встроенных функций вам нужно будет перекомпилировать или переустанавливать оболочку каждый раз, когда вносятся изменения в одну из этих встроенных функций.
can-ned_food
1

Многие ответили хорошо. Я намерен только дополнить эти ответы. Я думаю, что философия UNIX заключается в том, что инструмент должен делать одну вещь и делать это хорошо. Если кто-то пытается создать всеобъемлющий инструмент, у него гораздо больше мест для неудач. Ограничение функциональности таким образом делает набор инструментов надежным.

Кроме того, подумайте, если бы в оболочку были встроены такие функции, как sed или grep , было бы так легко вызывать их из командной строки, когда вам это нужно?

В заключение, рассмотрим некоторые функции, которые вы хотите использовать в BASH, в BASH . Например, возможность сопоставления RE в BASH реализована с использованием бинарного оператора = ~ (подробнее см. Грамматика оболочки на странице руководства , в частности, ссылка на обсуждение конструкции [[]] для if ). В качестве очень быстрого примера, скажем, я ищу в файле две шестнадцатеричные цифры:

while read line; do
    if [[ $line =~ 0x[[:xdigit:]]{2} ]]; then
        # do something important with it
    fi
done < input_file.txt

Что касается функциональности, подобной sed , смотрите в разделе «Расширение параметров» в заголовке «Расширение» той же справочной страницы. Вы увидите множество вещей, которые вы можете сделать, которые напоминают о sed. Я чаще всего использую sed, чтобы изменить тип замены на текст. Построение вышеперечисленного:

# this does not take into account the saving of the substituted text
# it shows only how to do it
while read line; do
    ${line/pattern/substitution}
done < input_file.txt

В конце концов, является ли выше "лучше", чем?

grep -E "[[:xdigit:]]{3}" input_file.txt
sed -e 's/pattern/substitution/' input_file.txt
Андрей Фаланга
источник
Аргумент против последнего вопроса можно найти по адресу unix.stackexchange.com/questions/169716/…
phk
1

Это, наверное, историческая случайность.

Когда UNIX был создан в конце 1960-х и начале 1970-х годов, компьютеры не имели почти столько же памяти, сколько сегодня. В то время было бы возможно реализовать всю эту функциональность в виде встроенных командных оболочек, но из-за ограничений памяти им пришлось бы ограничить объем функциональности, которую они могли бы реализовать, или рисковать из-за нехватки памяти и / или перестановки подкачки. проблемы.

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

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

Однако это не означает, что вы не можете реализовать некоторые функции дважды, и, действительно, некоторые оболочки реализуют некоторые функции, которые должны быть внешними программами в качестве встроенной оболочки; Например, Bash реализует echoкоманду как встроенную, но есть также/usr/bin/echo

Воутер Верхелст
источник