Распространено ли разделять больший сценарий на несколько сценариев и использовать их в основном сценарии?

23

На данный момент я разрабатываю больший скрипт Bash (это мой проект с открытым исходным кодом), и он начинает становиться беспорядком. Я разделил логику на функции, использую локальные переменные, где только могу, и объявил лишь несколько глобальных переменных. Тем не менее, это становится довольно сложно поддерживать.

Я думал о том, чтобы разбить сценарий на несколько сценариев и использовать их в своем основном сценарии (аналогично импорту на других языках).

Но мне интересно, если это осуществимый подход. Во-первых, использование нескольких сценариев может серьезно замедлить время выполнения сценария, а во-вторых, это усложняет распространение.

Итак, это хороший подход, и другие проекты с открытым исходным кодом делают это так же?

helpermethod
источник
4
Я искал действительно длинный сценарий оболочки и с 3500 строками и 125 КБ, я бы не хотел его поддерживать. Оболочка действительно дружелюбна при подключении программ, но когда она пытается выполнять вычисления, она становится довольно уродливой. Я знаю, что код, который у вас есть, в основном работает, и затраты на его перенос высоки, но вы можете рассмотреть кое-что еще в будущем.
MSW
1
Я столкнулся с той же проблемой. У меня умеренно большой bash проект sourceforge.net/projects/duplexpr . В настоящее время каждый сценарий самодостаточен, но я думаю перенести все общие функции в отдельный файл (ы) и включить их, где это необходимо, чтобы исключить необходимость их обновления в нескольких местах. В общем, я думаю, что было бы лучше просто вызывать каждый последующий скрипт, а не исходить из него. Это делает возможным выполнение деталей независимо друг от друга. Затем вы должны передать переменные в качестве аргументов или в файлах параметров (или вы можете просто экспортировать их, если вы не хотите автономно.)
Джо

Ответы:

13

Да, это обычная практика. Например, в первые дни Unix код оболочки, отвечающий за руководство системой на всех этапах загрузки до многопользовательской работы, был одним файлом /etc/rc. Сегодня процесс загрузки контролируется многими сценариями оболочки, разбитыми по функциям, с общими функциями и переменными, полученными по мере необходимости из центральных мест. В дистрибутивах Linux, Mac, BSD все в разной степени приняли этот подход.

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

Является ли shell подходящим инструментом для работы в этот момент? Как разработчик, который столкнулся с проблемами перерастания кода, я могу вам сказать, что переписывать не следует, а вместо этого рассмотрите возможность разделения частей на что-то более подходящее для масштаба, который вы хотите расширить для своего приложения - возможно, python, ruby ​​или даже perl ?

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

JasonG
источник
Это именно то, что я собирался опубликовать.
zwol
особенно учитывая, что даже более старые ОС, такие как Solaris, теперь поставляются с perl, python и т. д. Одна из причин, по которой старые системы использовали сценарии оболочки, заключается в том, что оболочка гарантированно всегда была доступна, но более крупные Unices, такие как HP-UX и Solaris и AIX, не могли гарантировать включение других инструментов.
Тим Кеннеди
7

Если это облегчает ваше обслуживание, вы можете иметь оба. Разделите его на логические части, чтобы вы могли легко поддерживать его, а затем написать (например,) Makefile, чтобы собрать все вместе для распространения. Вы можете написать несколько быстрых сценариев для копирования функций из включаемого файла в выходной файл вместо sourceлиния или просто сделать что - то тривиальное , как это (вам придется повторно tabify это, как makeтребует вкладки):

all: myscript

myscript: includes/* body/*
    cat $^ > "$@" || (rm -f "$@"; exit 1)

Затем у вас есть «исходная» версия (используется для редактирования) и «бинарная» версия (используется для простой установки).

derobert
источник
1
Ага! Кто-то еще, кто использует простой подход кошки :)
Клейтон Стэнли
4

Сценарий может быть разбит, как вы описываете, - почти все может быть сделано. Я бы сказал, что «хорошим подходом» было бы разделить ваш большой сценарий, выяснить, где его части можно запускать как отдельный процесс, взаимодействуя через механизмы IPC.

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

Вы можете распространять программу установки, которая обрабатывает все это для вас, распаковывая файлы, размещая их в нужном месте, предлагая пользователю добавить что-то похожее export PROGRAMDIR=$HOME/lib/PROGRAMна файл ~ / .bashrc. Тогда основная программа может выйти из строя, если $PROGRAMDIRона не установлена ​​или не содержит ожидаемых файлов.

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

Arcege
источник
1

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

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

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

Брюс Эдигер
источник
1

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

if [[ ${1:-} ]] && declare -F | cut -d' ' -f3 | fgrep -qx -- "${1:-}"
then "$@"
else main "$@" # Try the main function if args don't match a declaration.
fi

Причина не sourceсостоит в том, чтобы избежать загрязнения окружающей среды и варианта.

solidsnack
источник
0

Вот мой пример того, как большой bash-скрипт может быть разбит на несколько файлов и затем встроен в один полученный скрипт: https://github.com/zinovyev/bash-project

Я использую Makefileдля этого:

TARGET_FILE = "target.sh"
PRJ_SRC = "${PWD}/src/main.sh"
PRJ_LIB = $(shell ls -d ${PWD}/lib/*) # All files from ./lib

export PRJ_LIB

SHELL := /bin/env bash
all: define_main add_dependencies invoke_main

define_main:
    echo -e "#!/usr/bin/env bash\n" > ${TARGET_FILE}
    echo -e "function main() {\n" >> ${TARGET_FILE}
    cat "${PRJ_SRC}" | sed -e 's/^/  /g' >> ${TARGET_FILE}
    echo -e "\n}\n" >> ${TARGET_FILE}

invoke_main:
    echo "main \$$@" >> ${TARGET_FILE}

add_dependencies:
    for filename in $${PRJ_LIB[*]}; do cat $${filename} >> ${TARGET_FILE}; echo >> ${TARGET_FILE}; done
Zinovyev
источник