Якщо Тьюринг-повнота були всі ми вимагали, ми б не мали жодних - або мов програмування на всіх , навіть не асемблері . Комп'ютерні програмісти просто записують у машинному коді , оскільки наші процесори також завершені Тьюрінгом.
Ще зовсім недавно ви не могли розраховувати на те, щоб мати повну сумісність з POSIX .
Багато систем, особливо старіші, технічно мають оболонку, сумісну з POSIX, десь у системі, але вона може не знаходитися в передбачуваному місці /bin/sh
. Якщо ви пишете сценарій оболонки, і він повинен працювати в багатьох системах, як тоді ви пишете рядок shebang ? Один із варіантів - продовжувати та користуватися /bin/sh
, але вибирайте обмежити себе діалектом оболонки до POSIX Bourne, якщо він запускається на такій системі.
Оболонки пре-POSIX Bourne навіть не мають вбудованої арифметики; вам доведеться зателефонувати expr
або bc
зробити це.
Навіть з оболонкою POSIX, ви не вистачаєте на асоціативні масиви та інші функції, які ми очікували знайти в мовах сценаріїв Unix, оскільки Perl вперше став популярним на початку 1990-х .
Цей факт історії означає, що існує десятиліття традиції ігнорування багатьох потужних особливостей сучасних інтерпретаторів сценаріїв сімейства Борна виключно тому, що ви не можете розраховувати на наявність їх скрізь.
Це триває і донині, насправді: Bash не отримав асоціативних масивів до версії 4 , але ви можете здивуватися, скільки систем, які все ще використовуються, базуються на Bash 3. Apple все ще постачає Bash 3 з macOS в 2017 році - мабуть, для причини ліцензування - і Unix / Linux сервери часто запускають все, крім недоторканих у виробництві, дуже довго, тому у вас може бути стабільна стара система, яка ще працює під керуванням Bash 3, наприклад, вікно CentOS 5. Якщо у вас є такі системи у вашому оточенні, ви не можете використовувати асоціативні масиви в скриптах оболонки, які повинні працювати на них.
Якщо ваша відповідь на цю проблему полягає в тому, що ви пишете лише сценарії оболонок для "сучасних" систем, то вам доведеться впоратися з тим, що остання загальна орієнтир для більшості оболонок Unix - це стандарт оболонки POSIX , який значною мірою не змінюється, оскільки це було Введено в 1989 році. Існує багато різних оболонок на основі цього стандарту, але всі вони різнилися в тій чи іншій мірі від цього стандарту. Для того, щоб асоціативні масиви знову bash
, zsh
і ksh93
всі вони мають цю функцію, але є кілька несовместимостей реалізації. Тоді ваш вибір - використовувати лише Bash або використовувати тільки Zsh, або лише використовувати ksh93
.
Якщо ваша відповідь на цю проблему полягає в тому, "так просто встановіть Bash 4" або ksh93
, або що інше, то чому б не "просто" встановити Perl або Python або Ruby замість цього Це у багатьох випадках неприпустимо; значення за замовчуванням мають значення.
Жоден з модулів підтримки мов скриптів сімейства Bourne .
Найближчим до модульної системи в сценарії оболонки є .
команда, яка називається source
в більш сучасних варіантах оболонки Bourne, яка не працює на декількох рівнях відносно належної модульної системи, основним з яких є пробіг імен .
Незалежно від мови програмування, людське розуміння починає позначатися, коли будь-який файл у більшій загальній програмі перевищує кілька тисяч рядків. Сама причина, по якій ми структуруємо великі програми в багато файлів, полягає в тому, що ми можемо абстрагувати їхній вміст максимум до речення або двох. Файл A - це аналізатор командного рядка, файл B - це мережевий насос вводу / виводу, файл C - проміжок між бібліотекою Z та рештою програми тощо. Коли ваш єдиний метод для збирання багатьох файлів в одну програму - це текстове включення , ви ставите обмеження на те, наскільки ваші програми можуть рости розумно.
Для порівняння, це було б так, якби мова програмування C не мала лінкера, а лише #include
заяви. Така С-полегшений говір не потрібні ключові слова , такі як extern
або static
. Ці функції існують, щоб дозволити модульність.
POSIX не визначає спосіб застосування змінних до однієї функції скрипту оболонки, тим більше до файлу.
Це ефективно робить усі змінні глобальними , що знову ж таки шкодить модульності та компонованості.
Для цього є рішення в оболонках після POSIX - звичайно bash
, в принаймні , ksh93
і zsh
хоча б - але це просто повертає вас до точки 1 вище.
Ефект цього можна побачити в посібниках зі стилів для написання макросів GNU Autoconf, де вони рекомендують встановити прізвища змінних з іменем самого макросу, що веде до дуже довгих імен змінних виключно для того, щоб знизити ймовірність зіткнення до близько нуль.
Навіть С кращий за цією оцінкою, на милю. Не тільки більшість програм C, написаних головним чином за допомогою локальних змінних функцій, C також підтримує масштабування блоків, що дозволяє декільком блокам в межах однієї функції повторно використовувати імена змінних без перехресного забруднення.
Мови програмування оболонки не мають стандартної бібліотеки.
Можна стверджувати, що стандартна бібліотека мови сценаріїв оболонок - це вміст PATH
, але це просто говорить про те, що для виконання будь-якого наслідку, сценарій оболонки повинен викликати іншу цілу програму, ймовірно, одну, написану більш потужною мовою почати з.
Не існує також широко використовуваного архіву бібліотек утиліти оболонок, як у CPAN Perl . Без великої доступної бібліотеки стороннього утилітного коду програміст повинен написати більше коду вручну, щоб вона була менш продуктивною.
Навіть не зважаючи на те, що більшість скриптів оболонок покладаються на зовнішні програми, зазвичай написані на С, щоб зробити щось корисне, є всі витрати pipe()
→ fork()
→ exec()
ланцюги викликів. Ця закономірність є досить ефективною в Unix, порівняно з IPC та запуском процесів на інших ОС, але тут вона ефективно замінює те, що ви робите, з викликом підпрограми іншою мовою сценаріїв, що ще набагато ефективніше. Це ставить серйозну шапку на верхню межу швидкості виконання сценарію оболонки.
Сценарії оболонки мають невелику вбудовану здатність підвищувати свою ефективність за допомогою паралельного виконання.
Bourne снарядів &
, wait
і трубопроводи для цього, але це в основному використовується тільки для складання кількох програм, а не для досягнення CPU або паралелізм введення / виведення. Ви, швидше за все, не зможете прив’язати ядра або наситити RAID-масив виключно сценарієм оболонок, і, якщо це зробити, ви могли б досягти набагато вищої продуктивності на інших мовах.
Трубопроводи, зокрема, є слабкими способами підвищення продуктивності за допомогою паралельного виконання. Це дозволяє лише дві програми працювати паралельно, і одна з двох, ймовірно, буде заблокована вводу / виводу з іншого або в інший в будь-який момент часу.
Є новоявлені шляху навколо цього, такі , як xargs -P
і GNUparallel
, але це просто переходить до пункту 4 вище.
Не маючи вбудованої можливості повною мірою використовувати переваги багатопроцесорних систем, сценарії оболонки завжди будуть повільнішими, ніж добре написана програма мовою, яка може використовувати всі процесори в системі. Щоб знову взяти цей configure
приклад сценарію GNU Autoconf , подвоєння кількості ядер у системі мало зробить для покращення швидкості, з якою він працює.
Мови сценаріїв оболонок не мають вказівників чи посилань .
Це заважає вам робити безліч речей, які легко виконуються іншими мовами програмування.
По-перше, неможливість опосередкованого посилання на іншу структуру даних в пам'яті програми означає, що ви обмежені вбудованими структурами даних . Ваша оболонка може мати асоціативні масиви , але як вони реалізовані? Існує кілька можливостей, кожен з яких має різний компроміс: червоно-чорні дерева , дерева AVL та хеш-таблиці - найпоширеніші, але є й інші. Якщо вам потрібен інший набір компромісів, ви застрягли, тому що без посилань у вас немає способу вручну розгорнути багато типів розширених структур даних. Ви застрягли в тому, що вам дали.
Або, можливо, вам потрібна структура даних, яка навіть не має адекватної альтернативи, вбудованої у ваш інтерпретатор сценарію оболонки, наприклад, спрямований ациклічний графік , який може знадобитися для моделювання графіка залежності . Я програмую десятиліттями, і єдиний спосіб, який я можу зробити, щоб це зробити в сценарії оболонки, було б зловживати файловою системою , використовуючи символьні посилання як недолікові посилання. Це таке рішення, яке ви отримуєте, коли покладаєтесь лише на повну цінність Тьюрінга, і це нічого не говорить про те, чи рішення це елегантне, швидке або зрозуміле.
Розширені структури даних - це лише одне використання для покажчиків та посилань. Існує купа інших програм для них , які просто неможливо зробити легко на мові сценаріїв сім'ї Борна.
Я міг би продовжувати і продовжувати, але я думаю, що ти тут зрозумієш. Простіше кажучи, існує багато більш потужних мов програмування для систем типу Unix.
Ви, мабуть, не знайдете більшої групи віруючих у корисності написання високопортативного діалекту оболонок Борна, ніж розробники GNU Autoconf, але їхнє власне творіння написане головним чином на Perl, плюс деякі m4
, і лише трохи шкаралупи сценарій; тільки вихід Autoconf - це чистий сценарій оболонки Bourne. Якщо це не ставить питання про те, наскільки корисна концепція "Борн скрізь", я не знаю, що буде.
Технічно кажучи, ні, як підказує ваше спостереження за повнотою Тюрінга.
Але це не те саме, що говорити про те, що довільно великі сценарії оболонок приємні для запису, легко налагоджувати або швидко виконувати.
Як тільки ви почнете говорити про використання сценаріїв оболонок так, як це було призначено, як клей для керування іншими програмами в PATH
, двері відкриваються, тому що тепер ви обмежуєтесь лише тим, що можна зробити іншими мовами програмування, а це - вам сказати взагалі не мають обмежень. Скрипт оболонки , який отримує весь його силу, викликавши до інших програм в PATH
не працює так швидко , як монолітні програми , написаних на більш потужних мовах, але це дійсно працювати.
І в цьому справа. Якщо вам потрібна програма для швидкого запуску, або якщо вона сама по собі повинна бути потужною, а не позичати владу у інших, ви не пишете її в оболонці.
Я б поставив підтримку інструменту налагодження приблизно на 20-му місці в списку функцій, необхідних для підтримки програмування в цілому. Цілий ряд програмістів значно більше покладаються на printf()
налагодження, ніж власні налагоджувачі, незалежно від мови.
sh
Скрипт ,configure
який використовується як частина процесу складання для дуже багато чого іпа * х пакетів не є «відносно простим».