W pracy często piszę skrypty basha. Mój przełożony zasugerował podzielenie całego skryptu na funkcje, podobnie jak w poniższym przykładzie:
#!/bin/bash # Configure variables declare_variables() { noun=geese count=three } # Announce something i_am_foo() { echo "I am foo" sleep 0.5 echo "hear me roar!" } # Tell a joke walk_into_bar() { echo "So these ${count} ${noun} walk into a bar..." } # Emulate a pendulum clock for a bit do_baz() { for i in {1..6}; do expr $i % 2 >/dev/null && echo "tick" || echo "tock" sleep 1 done } # Establish run order main() { declare_variables i_am_foo walk_into_bar do_baz } main
Czy jest jakiś powód, aby to robić poza „czytelnością” , co moim zdaniem mogłoby być równie dobrze ugruntowane z kilkoma dodatkowymi komentarzami i pewnymi odstępami między wierszami?
Czy to sprawia, że skrypt działa wydajniej (właściwie spodziewałbym się czegoś przeciwnego), czy też sprawia, że łatwiej jest zmodyfikować kod poza wspomniany powyżej potencjał czytelności? A może to naprawdę tylko preferencja stylistyczna?
Zwróć uwagę, że chociaż skrypt nie pokazuje tego dobrze, „kolejność uruchamiania” funkcji w naszych aktualnych skryptach jest zwykle bardzo liniowa – walk_into_bar
zależy od rzeczy, które i_am_foo
wykonał, a do_baz
działa na rzeczy skonfigurowane przez walk_into_bar
– więc możliwość dowolnej zamiany kolejności uruchamiania nie jest czymś, co zwykle byśmy robili. Na przykład nie chciałbyś nagle wstawiać declare_variables
po walk_into_bar
, co mogłoby zepsuć sprawę.
Przykładem tego, jak napisałbym powyższy skrypt, byłoby:
#!/bin/bash # Configure variables noun=geese count=three # Announce something echo "I am foo" sleep 0.5 echo "hear me roar!" # Tell a joke echo "So these ${count} ${noun} walk into a bar..." # Emulate a pendulum clock for a bit for i in {1..6}; do expr $i % 2 >/dev/null && echo "tick" || echo "tock" sleep 1 done
Komentarze
Odpowiedź
Zacząłem używać tego samego styl programowania basha po przeczytaniu wpisu na blogu Kfir Lavi „Defensive Bash Programming” . Podaje kilka dobrych powodów, ale osobiście uważam je za najważniejsze:
-
procedury stają się opisowe: znacznie łatwiej jest dowiedzieć się, jaka jest przypuszczalna część kodu do zrobienia. Zamiast ściany kodu, zobaczysz „Och, funkcja
find_log_errors
odczytuje ten plik dziennika pod kątem błędów”. Porównaj to ze znajdowaniem wielu wierszy awk / grep / sed, które użyj Bóg wie, jaki typ wyrażenia regularnego w środku długiego skryptu – nie masz pojęcia, co on tam robi, chyba że są tam komentarze. -
możesz debugować funkcje umieszczając w
set -x
iset +x
. Gdy wiesz, że reszta kodu działa prawidłowo, możesz użyć tej sztuczki, aby skupić się na debugowaniu tylko tej określonej funkcji. Jasne, możesz dołączyć fragmenty skryptu, ale co, jeśli jest to „długi fragment?” Łatwiej jest zrobić coś takiego:set -x parse_process_list set +x
-
drukowanie z użyciem
cat <<- EOF . . . EOF
. Używałem go już kilka razy, aby uczynić mój kod bardziej profesjonalnym. Ponadto funkcjaparse_args()
z funkcjągetopts
jest całkiem wygodna. Znowu to pomaga w czytelności, zamiast umieszczać wszystko w skrypcie jako gigantyczną ścianę tekstu. Wygodne jest również ponowne użycie.
I oczywiście jest to znacznie więcej czytelne dla kogoś, kto zna C, Javę lub Vala, ale ma ograniczone doświadczenie w bashu. Jeśli chodzi o wydajność, niewiele można zrobić – sam bash nie jest najbardziej wydajnym językiem, a ludzie wolą perl i python, jeśli chodzi o szybkość i wydajność.Możesz jednak nice
funkcję:
nice -10 resource_hungry_function
W porównaniu do wywoływania nice w każdym wierszu kodu, zmniejsza to ilość pisania ORAZ może być wygodnie używane, gdy chcesz, aby tylko część twojego skryptu działała z niższym priorytetem.
Uruchamianie funkcji w tle, moim zdaniem, pomaga również, gdy chcesz mieć całość kilka instrukcji do uruchomienia w tle.
Niektóre z przykładów, w których użyłem tego stylu:
- https://askubuntu.com/a/758339/295286
- https://askubuntu.com/a/788654/295286
- https://github.com/SergKolo/sergrep/blob/master/chgreeterbg.sh
Komentarze
- Nie jestem pewien, czy powinieneś traktować jakiekolwiek sugestie z tego artykułu bardzo poważnie. To prawda, ma kilka dobrych pomysłów, ale najwyraźniej nie jest to ktoś przyzwyczajony do skryptów powłoki. Nie pojedyncza zmienna w każdym z przykładów jest cytowana (!) i sugeruje użycie WIELKIEGO C Nazwy zmiennych ASE, co jest często bardzo złym pomysłem, ponieważ mogą kolidować z istniejącymi zmiennymi środowiska. Twoje punkty w tej odpowiedzi mają sens, ale wydaje się, że linkowany artykuł został napisany przez kogoś, kto jest przyzwyczajony do innych języków i próbuje narzucić swój styl bashowi.
- @terdon Wróciłem do artykułu i ponownie go przeczytałem. Jedynym miejscem, w którym autor wspomina nazywanie zmiennych dużymi literami, jest ” Immutable Global Variables „. Jeśli weźmiesz pod uwagę zmienne globalne jako te, które muszą znajdować się w środowisku funkcji ', wtedy warto uczynić je kapitałowymi. Na marginesie, instrukcja bash ' nie zawiera ' konwencja stanu dla wielkości liter. Nawet tutaj zaakceptowana odpowiedź mówi ” zwykle ” i jedyna ” standard ” jest opracowany przez Google, który nie ' nie reprezentuje całej branży IT.
- @terdon na innym miejscu, zgadzam się w 100% z tym, że w artykule należało wspomnieć o cytowaniu zmiennych, co zostało również wskazane w komentarzach na blogu. Nie ' nie oceniałbym też kogoś używającego tego stylu kodowania, niezależnie od tego, czy ' był ponownie używany w innym języku. Całe to pytanie i odpowiedzi wyraźnie wskazują na ' zalety i ' stopień, w jakim ponowne użycie w innym języku jest tutaj prawdopodobnie nieistotne.
- @terdon no cóż, artykuł został opublikowany jako część ” źródła ” materiał. Mogłem opublikować wszystko jako własne opinie, ale musiałem tylko przyznać, że niektóre rzeczy, których nauczyłem się z tego artykułu, i że wszystko to pochodziło z badań w czasie. Strona na linkach autora ' pokazuje, że ma dobre doświadczenie z Linuksem i ogólnie IT, więc ' d zgaduję, że artykuł nie ' Naprawdę to pokazuję, ale ufam Twojemu doświadczeniu, jeśli chodzi o Linuksa i skryptów powłoki, więc możesz mieć rację.
- To ' to doskonała odpowiedź, ale ' chciałbym również dodać, że zakres zmiennych w Bash jest dziwny. Z tego powodu wolę deklarować moje zmienne w funkcjach przy użyciu
local
i wywoływać wszystko za pomocą funkcjimain()
. To znacznie ułatwia zarządzanie i pozwala uniknąć potencjalnie kłopotliwej sytuacji.
Odpowiedź
Czytelność to jedno. Ale modularyzacja to nie tylko to. ( Półmodularyzacja może być bardziej poprawna w przypadku funkcji.)
W funkcjach możesz zachować niektóre zmienne lokalne, co zwiększa niezawodność , zmniejszając prawdopodobieństwo rzeczy się pogmatwały.
Kolejną zaletą funkcji jest możliwość ponownego użycia . Po zakodowaniu funkcji można ją zastosować w skrypcie wiele razy. Możesz również przenieść go do innego skryptu.
Twój kod może być teraz liniowy, ale w przyszłości możesz wejść w dziedzinę wielowątkowości lub wielowątkowości przetwarzanie w świecie Bash. Kiedy nauczysz się robić rzeczy w funkcjach, będziesz dobrze przygotowany do przejścia do równoległości.
Jeszcze jeden punkt do dodania. Jak zauważa Etsitpab Nioliv w poniższym komentarzu, przekierowanie z funkcji jako spójnej całości jest łatwe. Jest jednak jeszcze jeden aspekt przekierowań z funkcjami. Mianowicie, przekierowania można ustawić wzdłuż definicji funkcji. Np .:
f () { echo something; } > log
Teraz wywołania funkcji nie wymagają żadnych jawnych przekierowań.
$ f
Może to zaoszczędzić wielu powtórzeń, co ponownie zwiększa niezawodność i pomaga w utrzymaniu porządku.
Zobacz także
Komentarze
- Bardzo dobrze odpowiedź, chociaż byłoby znacznie lepiej, gdyby zostało podzielone na funkcje.
- Może dodaj, że funkcje umożliwiają importowanie tego skryptu do innego skryptu (używając
source
lub. scriptname.sh
i używaj tych funkcji tak, jakby były w nowym skrypcie. - To ' jest już uwzględnione w innej odpowiedzi.
- Doceniam to. Ale ' wolę, aby inni też byli ważni.
- Stałem w obliczu sprawy dzisiaj, gdzie musiałem przekierować część danych wyjściowych skryptu do pliku (aby wysłać go e-mailem) zamiast wyświetlać echo. Po prostu musiałem wykonać funkcję myFunction > > myFile, aby przekierować wyjście żądanych funkcji. Całkiem wygodne. Może być istotne.
Odpowiedź
W swoim komentarzu wspomniałem o trzech zaletach funkcji:
-
Łatwiej jest je testować i weryfikować poprawność.
-
Funkcje można łatwo ponownie wykorzystać (pozyskać) w przyszłych skryptach
-
Twój szef je lubi.
I nigdy nie lekceważ znaczenia liczby 3.
Chciałbym poruszyć jeszcze jedną kwestię:
… więc możliwość dowolnej zamiany kolejności uruchamiania nie jest czymś, co zwykle byśmy robili. Na przykład nie chciałbyś nagle wstawiać
declare_variables
powalk_into_bar
, co mogłoby zepsuć sprawę.
Aby skorzystać z rozbijania kodu na funkcje, należy postarać się, aby funkcje były jak najbardziej niezależne. Jeśli walk_into_bar
wymaga zmiennej, która nie jest używana gdzie indziej, wtedy ta zmienna powinna być zdefiniowana w walk_into_bar
i ustawiona jako lokalna. Proces rozdzielania kodu na funkcje i minimalizowania ich wzajemnych zależności powinien uczynić kod bardziej przejrzystym i prostszym .
Idealnie byłoby, gdyby funkcje były łatwe do testowania indywidualnie. Jeśli z powodu interakcji nie są one łatwe do przetestowania, oznacza to, że mogą skorzystać na refaktoryzacji.
Komentarze
- Ja ' twierdzę, że ' czasami można modelować i wymuszaj te zależności, zamiast refaktoryzacji, aby ich uniknąć (ponieważ jeśli jest wystarczająco dużo h z nich, a ' są wystarczająco włochate, co może po prostu prowadzić do przypadku, gdy rzeczy nie są już w ogóle modularyzowane w funkcje). Bardzo skomplikowany przypadek użycia kiedyś zainspirował framework do zrobienia tego .
- To, co powinno być podzielone na funkcje, powinno być, ale przykład posuwa się za daleko. Myślę, że jedyną, która naprawdę mnie niepokoi, jest funkcja deklaracji zmiennej. Zmienne globalne, zwłaszcza statyczne, należy definiować globalnie w specjalnie do tego celu skomentowanej sekcji. Zmienne dynamiczne powinny być lokalne dla funkcji, które ich używają i modyfikują.
- @Xalorous I ' widzieliśmy praktyki, w których zmienne globalne są zainicjowane w procedurze, jako pośredni i szybki krok przed opracowaniem procedury, która odczytuje ich wartość z zewnętrznego pliku … Zgadzam się, że oddzielenie definicji i inicjalizacji powinno być czystsze, ale rzadko trzeba się zginać, aby przejść do korzyść numer 3
;-)
Odpowiedź
Chociaż całkowicie się zgadzam z możliwością ponownego użycia , czytelnością i delikatnym całowaniem szefów, ale jest jeszcze jedna zaleta funkcji w bash : zakres zmiennej . Jak pokazuje LDP :
#!/bin/bash # ex62.sh: Global and local variables inside a function. func () { local loc_var=23 # Declared as local variable. echo # Uses the "local" builtin. echo "\"loc_var\" in function = $loc_var" global_var=999 # Not declared as local. # Therefore, defaults to global. echo "\"global_var\" in function = $global_var" } func # Now, to see if local variable "loc_var" exists outside the function. echo echo "\"loc_var\" outside function = $loc_var" # $loc_var outside function = # No, $loc_var not visible globally. echo "\"global_var\" outside function = $global_var" # $global_var outside function = 999 # $global_var is visible globally. echo exit 0 # In contrast to C, a Bash variable declared inside a function #+ is local ONLY if declared as such.
Nie widzę tego zbyt często w prawdziwym świecie skryptów powłoki, ale wydaje się to dobrym pomysłem w przypadku bardziej złożonych skryptów. Zmniejszenie spójności pomaga uniknąć błędów polegających na „ponownym przebiciu zmiennej oczekiwanej w innej części kodu” .
Wielokrotne użycie często oznacza utworzenie wspólnej biblioteki funkcji i source
umieszczenie tej biblioteki we wszystkich skryptach. To nie pomoże im działać szybciej, ale pomoże Ci pisać je szybciej.
Komentarze
- Niewiele osób wprost używa
local
, ale myślę, że większość ludzi piszących skrypty podzielone na funkcje nadal kieruje się zasadą projektowania. Użycielocal
po prostu utrudnia wprowadzanie błędów. -
local
udostępnia zmienne dla funkcji i ich dzieci, więc ' naprawdę fajnie jest mieć zmienną, którą można przekazać w dół od funkcji A, ale niedostępna dla funkcji B, która może chcieć mieć zmienną o tej samej nazwie, ale innym przeznaczeniu.Aby ' było dobre do zdefiniowania zakresu, i jak powiedział Voo – mniej błędów
Odpowiedz
Dzielisz kod na funkcje z tego samego powodu, dla którego zrobiłbyś to dla C / C ++, pythona, perla, ruby czy jakiegokolwiek innego kodu języka programowania. Głębszym powodem jest abstrakcja – można hermetyzować zadania niższego poziomu w prymitywy (funkcje) wyższego poziomu, dzięki czemu nie trzeba przejmować się tym, jak to się robi. logika programu staje się jaśniejsza.
Jednak patrząc na twój kod, wydaje mi się dość dziwne, gdy mam funkcję deklarowania zmiennych; to naprawdę sprawia, że jestem uniesiony.
Komentarze
- Niedoceniona odpowiedź IMHO. Czy sugerujesz więc zadeklarowanie zmiennych w
main
funkcji / metodzie?
Odpowiedź
Zupełnie inny powód niż te podane w innych odpowiedziach: jeden z powodów, dla których ta technika jest czasami używana, gdzie jedyny instrukcja niebędąca definicją funkcji na najwyższym poziomie to wywołanie main
, mające na celu upewnienie się, że skrypt nie zrobi przypadkowo niczego nieprzyjemnego, jeśli zostanie obcięty. Skrypt może zostać obcięty Jeśli to jest przesłane potokiem z procesu A do procesu B (powłoka), a proces A kończy się z dowolnego powodu przed zakończeniem pisania całego skryptu. Jest to szczególnie prawdopodobne, jeśli proces A pobiera skrypt ze zdalnego zasobu. Chociaż ze względów bezpieczeństwa nie jest to dobry pomysł, należy to zrobić, a niektóre skrypty zostały zmodyfikowane, aby przewidzieć problem.
Komentarze
- Ciekawe! Ale niepokoi mnie to, że trzeba się tym zająć w każdym z programów. Z drugiej strony, dokładnie ten wzorzec
main()
jest typowy w Pythonie, gdzie używa sięif __name__ == '__main__': main()
na końcu pliku. - Idiom Pythona ma tę zaletę, że pozwala innym skryptom
import
na bieżący skrypt bez uruchamianiamain
. Przypuszczam, że podobną ochronę można by umieścić w skrypcie basha. - @Jake Cobb Tak. Robię to teraz we wszystkich nowych skryptach basha. Mam skrypt zawierający podstawową infrastrukturę funkcji używanych przez wszystkie nowe skrypty. Ten skrypt może zostać pobrany lub wykonany. Jeśli jest pozyskiwany, jego główna funkcja nie jest wykonywana. Wykrywanie źródła i wykonania odbywa się poprzez fakt, że BASH_SOURCE zawiera nazwę wykonywanego skryptu. Jeśli ' jest taki sam jak skrypt podstawowy, skrypt jest wykonywany. W przeciwnym razie ' jest pobierany.
- Ściśle związane z tą odpowiedzią bash używa prostego przetwarzania liniowego podczas uruchamiania z pliku znajdującego się już na dysku. Jeśli plik ulegnie zmianie w trakcie działania skryptu, licznik linii nie ' t się nie zmieni i ' będzie kontynuował w niewłaściwym wierszu. Hermetyzacja wszystkiego w funkcjach zapewnia, że ' wszystko jest załadowane do pamięci przed uruchomieniem czegokolwiek, więc zmiana pliku nie ' nie ma na to wpływu.
Odpowiedź
Kilka istotnych truizmów dotyczących programowania:
- Twój program się zmieni, , nawet jeśli twój szef twierdzi, że tak nie jest.
- Tylko kod i dane wejściowe mają wpływ na zachowanie programu.
- Nazywanie jest trudne.
Komentarze zaczynają się jako furtka, ponieważ nie są w stanie jasno wyrazić swoje pomysły w kodzie * i pogarszać się (lub po prostu źle) wraz ze zmianami. Dlatego, jeśli to w ogóle możliwe, wyrażaj pojęcia, struktury, rozumowanie, semantykę, przepływ, obsługę błędów i wszystko inne związane z rozumieniem kodu jako kod.
To powiedziawszy, Funkcje Bash mają pewne problemy, których nie ma w większości języków:
- Przestrzenie nazw są straszne w Bash. Na przykład zapomnienie o użyciu słowa kluczowego
local
powoduje zanieczyszczenie globalnej przestrzeni nazw. - Użycie
local foo="$(bar)"
skutkuje utrata kodu zakończeniabar
. - Nie ma nazwane parametry, więc musisz pamiętać, co
"$@"
oznacza w różnych kontekstach.
* Przepraszam, jeśli to urazi, ale potem używanie komentarzy przez kilka lat i rozwijanie bez nich ** przez wiele lat jest całkiem jasne, co jest lepsze.
** Używanie komentarzy do licencjonowania, dokumentacji API i tym podobnych jest nadal konieczne.
Komentarze
- Ustawiłem prawie wszystkie zmienne lokalne, deklarując je na null na początku funkcji …
local foo=""
Następnie ustawianie ich za pomocą wykonywania poleceń do działania na wyniku …foo="$(bar)" || { echo "bar() failed"; return 1; }
. To pozwala nam szybko wyjść z funkcji, gdy nie można ustawić wymaganej wartości. Nawiasy klamrowe są niezbędne, aby zapewnić, żereturn 1
jest wykonywany tylko w przypadku niepowodzenia. - Chciałem tylko skomentować swoje wypunktowane punkty. Jeśli używasz ' funkcji podpowłoki ' (funkcje rozdzielane nawiasami, a nie nawiasami klamrowymi), 1) nie ' nie muszę używać lokalnego, ale czerpać korzyści z lokalnego, 2) Nie ' nie napotykaj problemu utraty kodu zakończenia podstawiania poleceń w
local foo=$(bar)
tyle (ponieważ ' nie używasz lokalnego) 3) Nie ' nie musisz się martwić o przypadkowym zanieczyszczeniu lub zmianie zasięgu globalnego 4) są w stanie przekazać ' nazwane parametry ', które są ' local ' do swojej funkcji, używając składnifoo=bar baz=buz my-command
Odpowiedź
Proces wymaga sekwencji. Większość zadań jest sekwencyjna. Nie ma sensu zepsuć zamówienia.
Ale największą rzeczą w programowaniu – co obejmuje pisanie skryptów – jest testowanie. Testowanie, testowanie, testowanie. Jakie skrypty testowe posiadasz obecnie, aby sprawdzić poprawność swoich skryptów?
Twój szef próbuje Cię poprowadzić od bycia skrypciarzem do bycia programistą. To dobry kierunek. Ludzie, którzy przyjdą po ciebie, polubią cię.
ALE. Zawsze pamiętaj o swoich korzeniach zorientowanych na proces. Jeśli ma sens uporządkowanie funkcji w kolejności, w jakiej są one zwykle wykonywane, zrób to, przynajmniej jako pierwszy przebieg.
Później zobaczysz, że niektóre funkcje są przetwarzanie danych wejściowych, inne dane wyjściowe, inne przetwarzanie, inne modelowanie danych i inne manipulowanie danymi, więc może być rozsądne zgrupowanie podobnych metod, być może nawet przeniesienie ich do oddzielnych plików.
Później możesz zdajesz sobie sprawę, że napisałeś już biblioteki małych funkcji pomocniczych, których używasz w wielu swoich skryptach.
Odpowiedź
Komentarze a odstępy nie mogą nie zbliżyć się do czytelności, jaką zapewniają funkcje, jak to pokażę. Bez funkcji nie można zobaczyć lasu dla drzew – duże problemy kryją się w wielu liniach szczegółów. Innymi słowy, ludzie nie mogą jednocześnie skupiać się na drobnych szczegółach i na ogólnym obrazie. To może nie być oczywiste w krótkim scenariuszu; dopóki jest krótki, może być wystarczająco czytelny. Oprogramowanie staje się większe, a nie mniejsze iz pewnością jest to część całego systemu oprogramowania Twojej firmy, który z pewnością jest znacznie większy, prawdopodobnie miliony linii.
Zastanów się, czy dałem ci takie instrukcje:
Place your hands on your desk. Tense your arm muscles. Extend your knee and hip joints. Relax your arms. Move your arms backwards. Move your left leg backwards. Move your right leg backwards. (continue for 10,000 more lines)
Zanim osiągnąłeś połowę, a nawet 5%, zapomniałeś, jakie było kilka pierwszych kroków. Najprawdopodobniej nie można było dostrzec większości problemów, ponieważ nie można było zobaczyć lasu dla drzew. Porównaj z funkcjami:
stand_up(); walk_to(break_room); pour(coffee); walk_to(office);
To z pewnością dużo bardziej zrozumiałe, bez względu na to, ile komentarzy możesz umieścić w wersji sekwencyjnej wiersz po wierszu. sprawia też, że o wiele bardziej prawdopodobne jest, że „zauważysz, że zapomniałeś zrobić kawę, a prawdopodobnie zapomniałem o sit_down () na końcu. Kiedy twój umysł myśli o szczegółach wyrażeń regularnych grep i awk, nie możesz myśleć z szerszej perspektywy – „a co jeśli nie zaparzy się kawy”?
Funkcje przede wszystkim pozwalają zobaczyć duży obraz, i zauważ, że zapomniałeś zrobić kawy (lub że ktoś woli herbatę). Kiedy indziej, z innym nastawieniem, martwisz się o szczegółową implementację.
Są też inne korzyści omówione w oczywiście inne odpowiedzi Kolejną korzyścią, która nie została jasno określona w innych odpowiedziach, jest to, że funkcje zapewniają gwarancję, która jest ważna w zapobieganiu i naprawianiu błędów. Jeśli odkryjesz, że jakaś zmienna $ foo we właściwej funkcji walk_to () była błędna, wiesz, że wystarczy spojrzeć na pozostałe 6 wierszy tej funkcji, aby znaleźć wszystko, na co ten problem mógł mieć wpływ, i wszystko, co mogłoby spowodowały, że było to złe. Bez (odpowiednich) funkcji wszystko w całym systemie może być przyczyną niepoprawności $ foo, a $ foo może mieć wpływ na wszystko i wszystko. Dlatego nie możesz bezpiecznie naprawić $ foo bez ponownego sprawdzania każdej pojedynczej linii programu. Jeśli $ foo jest lokalna dla funkcji, możesz zagwarantować, że wszelkie zmiany są bezpieczne i poprawne, sprawdzając tylko tę funkcję.
Komentarze
- To nie jest ' t
bash
składnia.Jednak ' to wstyd; Nie ' nie sądzę, że istnieje sposób przekazywania danych wejściowych do takich funkcji. (tj.pour();
<coffee
). Wygląda bardziej jakc++
lubphp
(myślę). - @ tjt263 bez nawiasów, to ' składnia bash s: wlać kawę. Dzięki parens ' jest prawie każdym innym językiem. 🙂
Odpowiedź
Czas to pieniądz
Istnieją inne dobre odpowiedzi , które rzucają światło na techniczne powody, aby napisać modułowo skrypt, potencjalnie długi, opracowany w środowisku pracy, przeznaczony do użytku grupy osób , a nie tylko do własnego użytku.
Chcę skoncentruj się na jednym oczekiwaniu: w środowisku pracy „czas to pieniądz” . Tak więc brak błędów i wydajność Twojego kodu są oceniane razem z czytelnością , testowalnością, utrzymywalnością, refaktoryzacją, wielokrotnego użytku …
Pisanie w ” moduły „ kod skróci czas odczytu potrzebny nie tylko samemu koderowi , ale nawet czasowi używanemu przez testerów lub przez szef. Co więcej, pamiętaj, że czas szefa jest zwykle opłacany więcej niż czas programisty i że szef oceni jakość Twojej pracy.
Ponadto pisząc w niezależne „moduły” kod (nawet skrypt basha) umożliwi Ci pracę w „równolegle” z inny komponent twojego zespołu skracający całkowity czas produkcji i wykorzystujący co najwyżej doświadczenie jednego z nich, do przejrzenia lub przepisania części bez skutków ubocznych dla innych, do ponownego wykorzystania napisanego kodu „tak jak jest” dla innego programu / skryptu, aby utworzyć biblioteki (lub biblioteki fragmentów), aby zmniejszyć całkowity rozmiar i związane z nim prawdopodobieństwo błędów, aby debugować i przetestować dokładnie każdą pojedynczą część … i oczywiście zorganizuje się w logiczny podziel swój program / skrypt i popraw jego czytelność. Wszystko, co pozwoli zaoszczędzić czas, a więc pieniądze. Wadą jest to, że musisz trzymać się standardów i komentować swoje funkcje (że nie masz nie do zrobienia w środowisku pracy).
Przestrzeganie standardu spowolni Twoją pracę na początku, ale później przyspieszy pracę wszystkich innych (i Ciebie). Rzeczywiście, gdy współpraca rośnie w liczbę zaangażowanych osób, staje się to nieuniknioną potrzebą. Na przykład, nawet jeśli uważam, że zmienne globalne muszą być definiowane globalnie , a nie w funkcji, rozumiem standard, który inicjalizuje je w funkcji o nazwie declare_variables()
wywoływane zawsze w pierwszym wierszu main()
jednego …
Wreszcie, nie lekceważ możliwości w nowoczesnym kodzie źródłowym edytory do pokazywania lub ukrywania selektywnie oddzielnych procedur ( Składanie kodu ). Pozwoli to zachować kompaktowy kod i skoncentrować się na ponownym zapisywaniu przez użytkownika.
Powyżej możesz zobaczyć, jak jest rozwinięta tylko funkcja walk_into_bar()
. Nawet pozostałe miały po 1000 wierszy, więc nadal można było kontrolować cały kod na jednej stronie. Zwróć uwagę, że jest on zawijany nawet w sekcji, w której chcesz zadeklarować / zainicjować zmienne.
Odpowiedź
Inny powód często pomijana jest analiza składni basha:
set -eu echo "this shouldn"t run" { echo "this shouldn"t run either"
Ten skrypt oczywiście zawiera błąd składniowy i bash nie powinien go w ogóle uruchamiać, prawda? Źle.
~ $ bash t1.sh this shouldn"t run t1.sh: line 7: syntax error: unexpected end of file
Gdybyśmy opakowali kod w funkcję, to by się nie zdarzyło:
set -eu main() { echo "this shouldn"t run" { echo "this shouldn"t run either" } main
~ $ bash t1.sh t1.sh: line 10: syntax error: unexpected end of file
Odpowiedź
Oprócz powodów podanych w innych odpowiedziach:
- Psychologia: programista, którego produktywność jest mierzona w wierszach kodu, będzie miał zachętę do pisania niepotrzebnie rozwlekłego kodu. Im więcej zarządzania wymaga koncentrując się na wierszach kodu, tym większą motywację ma programista, aby rozszerzyć swój kod o niepotrzebną złożoność.Jest to niepożądane, ponieważ zwiększona złożoność może prowadzić do zwiększonych kosztów utrzymania i zwiększonego wysiłku wymaganego do naprawy błędów.
Komentarze
- To nie jest taka zła odpowiedź, jak mówią głosy przeciwne. Uwaga: agc mówi, że również jest to możliwość i tak jest. Nie ' nie mówi, że byłaby to jedyna możliwość, i nie ' nikogo nie oskarża, a jedynie przedstawia fakty. Chociaż wydaje mi się, że dzisiaj jest prawie niespotykana bezpośrednia ” linia kodu ” – > ” $$ ” styl pracy kontraktowej, pośrednio oznacza to dość często, że tak, masa wyprodukowanego kodu liczy się przez liderów / bosses.
main()
na górze i dodajęmain "$@"
na dole, aby to nazwać. To pozwala zobaczyć najwyższe logika skryptu poziomu pierwsza rzecz po otwarciu.local
– zapewnia zmienną zasięg , która jest niezwykle ważna w każdym nietrywialnym skrypcie.