Чи загально розділяти більший скрипт на кілька сценаріїв та джерело їх у головному сценарії?


23

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

Я думав розбити сценарій на декілька сценаріїв та вивести їх у свій основний сценарій (подібний до імпорту іншими мовами).

Але мені цікаво, чи це здійсненний підхід. По-перше, пошук декількох скриптів може сильно уповільнити час виконання сценарію, по-друге, це ускладнює розповсюдження.

Отже, чи це хороший підхід, і чи інші проекти (з відкритим кодом) роблять це так само?


4
Я пішов шукати дійсно довгий сценарій оболонки, а в 3500 рядків і 125 КБ, я не хотів би намагатися його підтримувати. Оболонка дійсно доброзичлива при підключенні програм, але коли вона намагається робити обчислення, вона стає досить некрасивою. Я знаю, що у вас працює здебільшого код, і витрати на його перенесення є високими, але ви, можливо, захочете розглянути щось інше в майбутньому.
msw

1
Я зіткнувся з тією ж проблемою. У мене помірно великий проект bash sourceforge.net/projects/duplexpr . Наразі кожен сценарій є автономним, але я думаю про переміщення всіх загальних функцій в окремий файл (и) та включення їх там, де потрібно, щоб усунути необхідність оновлення їх у кількох місцях. Взагалі, я думаю, що було б краще просто викликати кожен наступний сценарій, а не його джерело. Це робить можливим запуск деталей незалежно. Потім вам потрібно передавати змінні у вигляді аргументів або у файли параметрів (або ви можете просто експортувати їх, якщо ви не хочете самостійно.)
Джо,

Відповіді:


13

Так, це звичайна практика. Наприклад, в перші дні Unix оболонки код відповідає за керівництво системою через її завантаження фаз на багато користувачів режим був один файл, /etc/rc. Сьогодні процес завантаження контролюється багатьма скриптами оболонки, розділеними за функціями, із загальними функціями та змінними, які необхідні для централізованих локацій. Дистрибутиви Linux, Macs, BSD, в тій чи іншій мірі прийняли такий підхід.


2
хоча в цьому випадку це більше для повторного використання. Різні сценарії використовують загальну бібліотеку функцій оболонок.
Стефан Шазелас

16

Чи справді оболонка є правильним інструментом для роботи? Як розробник, який наткнувся на проблеми переростання коду, я можу вам сказати, що перезапис не слід розглядати, а замість цього розглянути питання про відокремлення фрагментів на щось, що краще підходить для того масштабу, який ви хочете, щоб розробити свою програму - можливо, python, ruby ​​або навіть perl ?

Shell - це корисна мова - це мова сценаріїв - і тому важко буде виростити її до тих розмірів.


Це саме те, що я збирався розмістити.
zwol

особливо враховуючи, що навіть більш старі ОС, такі як Solaris, зараз постачаються з perl та python тощо. Однією з причин, що в старих системах використовуються сценарії оболонок, є те, що оболонка гарантувалась, що вона завжди буде доступною, але більші Unice, як-от HP-UX та Solaris та AIX, не могли гарантувати включення інших інструментів.
Тім Кеннеді

7

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

all: myscript

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

Потім у вас є "вихідна" версія (використовується для редагування) та "двійкова" версія (використовується для тривіальної установки).


1
Ага! Хтось хто використовує простий підхід до котів :)
Клейтон Стенлі

4

Сценарій може бути розбитий, як ви описуєте - майже все можна зробити. Я б сказав, що "хорошим підходом" було б розділити свій великий сценарій, з'ясувати, де його частини можна провести як окремий процес, спілкуючись через механізми IPC.

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

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

Я б не хвилювався настільки, як витрачався на завантаження інших сценаріїв. Накладні дані справді просто відкривають файл; обробка тексту однакова, особливо якщо вони є функціональними визначеннями.


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полягає в тому, щоб уникнути забруднення навколишнього середовища та варіантів забруднення.


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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.