Czy często dzieli się większy skrypt na wiele skryptów i umieszcza je w skrypcie głównym?


23

W tej chwili pracuję nad większym skryptem Bash (jest to mój projekt Open Source) i zaczyna się robić bałagan. Podzieliłem logikę na funkcje, używam zmiennych lokalnych, gdzie mogę i zadeklarowałem tylko garść zmiennych globalnych. Mimo to utrzymanie go jest dość trudne.

Pomyślałem o podzieleniu skryptu na wiele skryptów i umieszczenie ich w głównym skrypcie (podobnie jak w importach w innych językach).

Ale zastanawiam się, czy jest to realne podejście. Po pierwsze, pozyskiwanie wielu skryptów może znacznie spowolnić czas wykonywania skryptu, a po drugie utrudnia dystrybucję.

Czy to jest dobre podejście i czy inne projekty (Open Source) robią to w ten sam sposób?


4
Szukałem na naprawdę długi skrypcie i na 3500 linii i 125KB, nie chciałby, aby spróbować utrzymać. Powłoka jest naprawdę przyjazna podczas podłączania programów, ale kiedy próbuje wykonać obliczenia, robi się dość brzydka. Wiem, że kod, który masz przeważnie działa, a koszty jego przenoszenia są wysokie, ale możesz rozważyć coś innego w przyszłości.
msw

1
Natrafiłem na ten sam problem. Mam umiarkowanie duży projekt bash sourceforge.net/projects/duplexpr . Obecnie każdy skrypt jest samodzielny, ale myślę o przeniesieniu wszystkich typowych funkcji do osobnych plików i dołączeniu ich tam, gdzie to konieczne, aby wyeliminować konieczność ich aktualizacji w wielu miejscach. Ogólnie rzecz biorąc, myślę, że lepiej byłoby wywołać każdy kolejny skrypt, niż go źródłować. Umożliwia niezależne prowadzenie części. Następnie musisz przekazać zmienne jako argumenty lub w plikach parametrów (lub możesz je po prostu wyeksportować, jeśli nie chcesz samodzielnego.)
Joe

Odpowiedzi:


13

Tak, jest to powszechna praktyka. Na przykład, w pierwszych dniach Unix Shellcode odpowiedzialne za kierowanie systemem za pomocą fazy rozruchu do pracy wieloużytkownikowej był pojedynczy plik /etc/rc. Obecnie proces rozruchu jest kontrolowany przez wiele skryptów powłoki, podzielonych według funkcji, z typowymi funkcjami i zmiennymi pozyskiwanymi w razie potrzeby z centralnych lokalizacji. Dystrybucje Linuksa, komputery Mac, BSD w różnym stopniu przyjęły to podejście.


2
choć w takim przypadku chodzi raczej o możliwość ponownego użycia. Różne skrypty używają wspólnej biblioteki funkcji powłoki.
Stéphane Chazelas

16

Czy shell jest w tym momencie właściwym narzędziem do pracy? Jako programista, który wpadł na problemy związane z przerastaniem kodu, mogę powiedzieć, że przepisanie nie powinno być brane pod uwagę, ale zamiast tego rozważenie rozdzielenia elementów na coś lepiej dopasowanego do skali, w której chcesz rozwinąć swoją aplikację - na przykład python, ruby ​​lub nawet perl ?

Shell to język narzędziowy - to język skryptowy - dlatego trudno będzie go rozwinąć do takich rozmiarów.


Właśnie to miałem zamiar opublikować.
zwolnić

Zwłaszcza biorąc pod uwagę, że nawet starsze systemy operacyjne, takie jak Solaris, są teraz dostarczane z Perlem, Pythonem itp. Jednym z powodów, dla których starsze systemy korzystały ze skryptów powłoki, jest to, że powłoka była zawsze dostępna, ale większe Unices, takie jak HP-UX i Solaris oraz AIX, nie mogły zagwarantować, że będą zawierać inne narzędzia.
Tim Kennedy,

7

Jeśli ułatwia to konserwację, możesz mieć jedno i drugie. Podziel go na logiczne części, abyś mógł go łatwo utrzymywać, a następnie napisz (np.) Plik Makefile, aby złożyć go z powrotem do dystrybucji. Możesz napisać kilka szybkich skryptów, aby skopiować funkcje z pliku dołączania do pliku wyjściowego zamiast sourcelinia lub po prostu zrobić coś tak trywialnego (musisz to ponownie tabify, jak makewymaga kart):

all: myscript

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

Następnie masz wersję „źródłową” (używaną do edycji) i wersję „binarną” (używaną do trywialnej instalacji).


1
Aha! Ktoś inny, kto używa prostego podejścia kota :)
Clayton Stanley

4

Skrypt można zepsuć w miarę opisywania - prawie wszystko można zrobić. Powiedziałbym, że „dobrym podejściem” byłoby podzielenie twojego dużego skryptu na przedziały, dowiedzieć się, gdzie jego części można uruchomić jako osobny proces, komunikując się za pośrednictwem mechanizmów IPC.

Poza tym dla skryptu powłoki spakowałbym go jako pojedynczy plik. Jak mówisz, utrudnia to dystrybucję: albo musisz wiedzieć, gdzie znajdują się skrypty „biblioteczne” - nie ma ładnego standardu dla skryptów powłoki - albo polegać na tym, że użytkownik prawidłowo ustawi swoją ścieżkę.

Możesz rozpowszechniać program instalacyjny, który obsługuje to wszystko za Ciebie, rozpakowując pliki, umieszczając je we właściwym miejscu, informując użytkownika o dodaniu czegoś takiego export PROGRAMDIR=$HOME/lib/PROGRAMdo pliku ~ / .bashrc. Wtedy główny program może zawieść, jeśli $PROGRAMDIRnie jest ustawiony lub nie zawiera oczekiwanych plików.

Nie martwiłbym się tak bardzo o obciążenie związane z ładowaniem innych skryptów. Narzutem jest po prostu otwarcie pliku; przetwarzanie tekstu jest takie samo, szczególnie jeśli są to definicje funkcji.


1

Powszechna praktyka czy nie, nie sądzę, aby pozyskiwanie czegokolwiek innego niż zestaw eksportu było dobrym pomysłem. Uważam, że wykonywanie kodu przez pozyskiwanie jest po prostu mylące i ogranicza ponowne użycie, ponieważ ustawienia środowiskowe i inne zmienne bardzo uzależniają kod źródłowy od kodu źródłowego.

Lepiej jest podzielić aplikację na mniejsze, samodzielne skrypty, a następnie wykonać je jako serię poleceń. Ułatwi to debugowanie, ponieważ można wykonać każdy samodzielny skrypt w interaktywnej powłoce, sprawdzając pliki, dzienniki itp. Między każdym wywołaniem polecenia. Twój pojedynczy, duży skrypt aplikacji zamienia się w prostszy skrypt sterujący, który uruchamia serię poleceń po zakończeniu debugowania.

Grupa mniejszych, samodzielnych skryptów napotyka na trudniejszy do zainstalowania problem.


1

Alternatywą dla pozyskiwania skryptów jest po prostu wywoływanie ich za pomocą argumentów. Jeśli już podzieliłeś większość swojej funkcjonalności na funkcje powłoki, prawdopodobnie jesteś już prawie w stanie to zrobić. Poniższy fragment Bash pozwala na użycie dowolnej funkcji zadeklarowanej w skrypcie jako podkomendy:

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

Powodem tego sourcejest unikanie zanieczyszczenia środowiska i opcji zanieczyszczenia.


0

Oto mój przykład tego, jak duży skrypt bash można podzielić na wiele plików, a następnie wbudować w jeden wynikowy skrypt: https://github.com/zinovyev/bash-project

Używam Makefiledo tego celu:

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.