Вопрос или проблема
После некоторого гугления я нашел способ компилировать BASH-скрипты в исполняемые бинарные файлы (с помощью shc
).
Я знаю, что оболочка является интерпретируемым языком, но что делает этот компилятор? Улучшит ли он производительность моего скрипта каким-либо образом?
Чтобы ответить на вопрос в вашем заголовке, скомпилированные shell-скрипты могут быть лучше для производительности — если результат компиляции будет представлять результат интерпретации без необходимости повторного интерпретирования команд в скрипте. Смотрите, например, shcomp
в ksh93
, zcompile
в zsh
или развивающийся Bunster для bash
.
Однако shc
не компилирует скрипты таким образом. Это не настоящий компилятор, это инструмент “шифрования” скрипта с различными методами защиты сомнительной эффективности. Когда вы компилируете скрипт с помощью shc
, результатом является бинарный файл, содержимое которого не сразу читается; когда он запускается, он расшифровывает свое содержимое и запускает инструмент, для которого был предназначен скрипт, с расшифрованным скриптом, что делает оригинальный скрипт легкодоступным (он передается целиком в командной строке интерпретатора, с добавленными пробелами в попытке усложнить его поиск). Поэтому общая производительность всегда будет хуже: помимо времени, потраченного на выполнение оригинального скрипта, добавляется время, потраченное на настройку среды и расшифровку скрипта.
После некоторого гугления я нашел способ компилировать BASH-скрипты в исполняемые бинарные файлы (с помощью
shc
).
Досадно, что это приспособление shc
все еще появляется в результатах поиска Google, даже после того, как оно было полностью развенчано за все эти годы: shc
не является компилятором и не предотвращает просмотр и “кражу” исходного кода скрипта.
Вообще, shc даже глупее, чем должно быть, потому что после снятия маскировки исходного кода скрипт просто передается как аргумент bash -c
, что делает его видимым в /proc/<pid>/cmdline
для любого пользователя, а не только для того, кто запускает скрипт. Это также сталкивается с ограничением длины одного аргумента командной строки в Linux (128k байт). Но чтобы сделать вещи еще более нелепыми, первая часть этого аргумента заполнена пробелами, чтобы он не появлялся в ps
😉
Улучшит ли он производительность моего скрипта каким-либо образом?
Да, ваш скрипт может вообще не работать, что означает, что он завершится быстрее.
В общем, нет способа скомпилировать shell-скрипт, потому что новый исходный текст может быть введен несколькими методами во время выполнения, которые, следовательно, обходят фазу компиляции. Этот новый исходный код не сможет взаимодействовать с скомпилированными функциями или переменными.
Два метода создания исходного кода во время выполнения:
Подключить сторонний файл, который мог быть создан или изменен после компиляции оригинального скрипта.
Создать во время выполнения произвольную команду в строке и исполнить ее.
.
Ответ или решение
Когда мы говорим о производительности скриптов на Shell, мы, как правило, подразумеваем несколько аспектов: скорость выполнения команд, размер и объем используемой памяти, а также эффективность использования ресурсов системы. Предполагается, что компилирование скриптов способно улучшить некоторые из этих аспектов. Однако важно учитывать, что термин "компилирование" может восприниматься различными способами в зависимости от подхода и инструмента.
Теоретическая основа
Shell-языки, такие как Bash, традиционно являются интерпретируемыми, что означает, что команды выполняются напрямую командной строкой или интерпретатором. Это позволяет получить взаимодействие в реальном времени и изменять скрипты "на лету". Основным недостатком является то, что каждоразовый анализ и выполнение команд занимает больше времени, особенно если скрипт содержит большие циклы или включает в себя сложные логические структуры.
В теоретическом смысле, компиляция подразумевает преобразование исходного кода в исполняемый двоичный формат, что снижает накладные расходы на интерпретацию и может ускорить выполнение. В классическом программировании, когда говорят о компиляции, обычно имеется в виду процесс преобразования высокоуровневого языкового кода в машинный код. Это действительно часто приводит к увеличению производительности.
Примеры существующих решений
В контексте скриптов Shell компиляция часто реализуется не так, как в традиционных языках программирования. Например, инструменты вроде shc
, shcomp
для ksh
или zcompile
для zsh
предоставляют различные механизмы для работы с Shell-скриптами. Важно заметить, что большинство таких инструментов, включая shc
, не являются настоящими компиляторами.
shc: Этот инструмент не столько компилирует скрипты, сколько применяет своего рода шифровку, создавая изначально не читаемый двоичный файл. Когда такой файл запускается, он расшифровывает данные и передает их в интерпретатор, например, в Bash. Это снижает производительность, так как добавляется предварительная обработка по расшифровке данных и подготовки окружения, прежде чем фактически начать выполнение скрипта.
shcomp и zcompile: Эти инструменты в некоторой степени ближе к компиляции, но также не обходятся без интерпретации. Они пре-компилируют скрипт, выполняя его синтаксический анализ заранее. Однако реальная польза от этого часто незначительная, особенно в условиях сложных динамических скриптов, где выполнение зависит от ввода или внесенного ранее кода.
Применение и выводы
Практически, каким бы заманчивым ни казался подход компиляции для повышения производительности, в случае Shell-скриптов он редко оправдывает ожидания. Современные интерпретаторы уже достаточно оптимизированы, чтобы интерпретация не была основным узким местом в их производительности. Обычно узким местом становится время, затрачиваемое на выполнение самих команд, особенно если это внешние программы или сложные вычислительные операции.
Кроме того, интерпретируемый характер Shell-скриптов предоставляет значительные преимущества в гибкости, возможности динамического формирования и выполнения команд, а также легкости модификации. Компиляция же, как правило, снижает эти преимущества за счет дополнительной статичности и ограничивает возможности изменения исходного кода без повторной процедуры компиляции.
Для улучшения производительности Shell-скриптов лучше сосредоточить усилия на оптимизации самого кода: использовать локальные переменные, избегать излишних циклов, минимизировать вызовы внешних программ, и адаптировать алгоритмы таким образом, чтобы они эффективно использовали ресурсы системы.
Таким образом, если рассматривать "компиляцию" Shell-скриптов с использованием shc
или схожих инструментов, улучшения в производительности скрипта достичь не удастся. Наоборот, это может лишь добавить ненужные накладные расходы. Для тех, кто желает защиты исходного кода, необходимо рассмотреть альтернативные механизмы, так как шифровка с использованием shc
не является надежным средством защиты.