Centrum skryptów - Systemy operacyjne

Jak wielokrotnie wykorzystywać funkcje?

Udostępnij na: Facebook

Skrypciarze odpowiadają na Wasze pytania

Cześć Skrypciarze!

Witamy w rubryce TechNet, w której Skrypciarze z firmy Microsoft odpowiadają na częste pytania dotyczące używania skryptów w administracji systemu. Jeśli macie jakieś pytania z tej dziedziny, zachęcamy do wysłania e-maila na adres: scripter@microsoft.com. Nie możemy zagwarantować odpowiedzi na każde otrzymane pytanie, ale staramy się jak możemy.

Jak wielokrotnie wykorzystywać funkcje?

Cześć Skrypciarze! Pytanie

Cześć, Skrypciarze! Dysponuję zestawem funkcji PowerShell, które chciałbym wykorzystać w wielu skryptach. Mam już dość ciągłego wycinania i wklejania tych elementów w różnych skryptach. Musi istnieć lepszy sposób! Jakieś pomysły?

-JB

Cześć Skrypciarze! Pytanie

Cześć, JB,

Oczywiście, że mam jakiś pomysł. Rozumiem, że napisałeś kilka funkcji i chciałbyś móc stosować je także w innych skryptach. Wielokrotne wykorzystywanie kodu to świetna idea. To właśnie nazywam ekologicznym podejściem do tworzenia skryptów (bezwstydnie zapożyczonym z zasady 3R): ogranicz ilość pracy, poddaj kod recyklingowi i użyj funkcji ponownie. Jak wspominałeś, najłatwiejszy sposób polega po prostu na skopiowaniu i wklejeniu funkcji z jednego skryptu do innego. Załóżmy, że mamy skrypt zawierający kod, który przeprowadza konwersję ze stopni Celsjusza na stopnie Fahrenheita i chcemy użyć tego algorytmu w innym skrypcie o odmiennej funkcjonalności. Możemy po prostu wkleić do niego fragment kodu skopiowany ze starego skryptu. W ten sposób otrzymamy skrypt podobny do następującego (nazwijmy go ConvertToFahrenheit.ps1):

Param($Celsius)

Function ConvertToFahrenheit($Celsius)

{

 "$Celsius Celsius equals $((1.8 * $Celsius) + 32) Fahrenheit"

} #end ConvertToFahrenheit

ConvertToFahrenheit($Celsius)

Powyższy skrypt jest całkiem prawidłowy. Realizuje jedną funkcję i wykonuje ją całkiem nieźle. Do wykonania skryptu używamy parametru wiersza polecenia. Plusem jest to, że wywołując skrypt, że nie musimy wpisywać całej nazwy parametru:

PS C:\> C:\ScriptingGuys\ConvertToFahrenheit.ps1 -c 24

24 celsius equals 75.2 fahrenheit

A zatem skoro już mamy ten bonzer’owy skrypt (korzystając z okazji, uczę się australijskiego), dlaczego mielibyśmy korzystać z czegoś innego? Cóż, wyobraźcie sobie, że jesteście Skrypciarzami z firmy Microsoft i od miesiąca włóczycie się po Australii. Prawdopodobnie przyda się Wam możliwość dokonywania także innych konwersji metrycznych, nie tylko ze stopni Celsiusa na Fahrenheita. Przypuśćmy, że napisaliśmy kilka różnych skryptów, które wykorzystują jedną lub więcej stworzonych przez nas funkcji konwersji. A teraz odkryliśmy, że funkcja ta zawiera literówkę w słowie "Celsius". Gdybyśmy zdecydowali się ją skorygować, musielibyśmy zidentyfikować wszystkie miejsca, w których wystąpiło niepoprawnie napisane słowo, a następnie poprawić błąd. Albo przypuśćmy, że chcemy zmienić format temperatury tak, aby wyświetlane były tylko dwa miejsca po przecinku. Ponownie musielibyśmy znaleźć wszystkie wystąpienia funkcji i dokonać zmian, w przeciwnym razie otrzymalibyśmy wiele nieco odmiennych wersji funkcji.

Jak rozwiązać ten problem? Jedno z podejść polega na umieszczeniu wszystkich funkcji w pojedynczym skrypcie. Możemy stworzyć następujący skrypt (nazwijmy go ConversionFunctions.ps1):

Function ConvertToMeters($feet)

{

  "$feet feet equals $($feet*.31) meters"

} #end ConvertToMeters

Function ConvertToFeet($meters)

{

 "$meters meters equals $($meters * 3.28) feet"

} #end ConvertToFeet

Function ConvertToFahrenheit($celsius)

{

 "$celsius celsius equals $((1.8 * $celsius) + 32 ) fahrenheit"

} #end ConvertToFahrenheit

Function ConvertTocelsius($fahrenheit)

{

 "$fahrenheit fahrenheit equals $( (($fahrenheit - 32)/9)*5 ) celsius"

} #end ConvertTocelsius

Function ConvertToMiles($kilometer)

{

  "$kilometer kilometers equals $( ($kilometer *.6211) ) miles"

} #end convertToMiles

Function ConvertToKilometers($miles)

{

  "$miles miles equals $( ($miles * 1.61) ) kilometers"

} #end convertToKilometers

Gdy chcemy użyć jednej z funkcji konwersji, dołączamy ją so skryptu, umieszczając kropkę na początku ścieżki do skryptu. Po dołączeniu skryptu zawierającego funkcje konwersji uzyskujemy dostęp do wszystkich funkcji i możemy wykorzystać je w sposób bezpośredni, zupełnie tak jak gdyby znajdowały się one w tym samym pliku. Skrypt ConvertToFahrenheit_Include.ps1 ilustruje to podejście. Temperaturę, którą chcemy przekonwertować, nadal dostarczamy przy pomocy parametru wiersza polecenia $celsius. Następnie wpisujemy kropkę, po której następuje ścieżka do dołączanego pliku skryptu. Na zakończenie wywołujemy funkcję, podając jej nazwę oraz wartość wprowadzoną do skryptu za pośrednictwem wiersza polecenia. Nowa wersja skryptu ConvertToFahrenheit.ps1 została zaprezentowana poniżej:

Param($Celsius)

$includeFile = “c:\data\scriptingGuys\ConversionFunctions.ps1”

. $includeFile

ConvertToFahrenheit($Celsius)

Jak widać, powyższy skrypt jest dużo bardziej uporządkowany i czytelny. Dzięki temu łatwiej jest go zrozumieć i tym samym łatwiej nim zarządzać. Oczywiście takie rozwiązanie pociąga za sobą pewne konsekwencje. Po pierwsze dwa skrypty są teraz powiązane ze sobą. Modyfikacja jednego z nich wpłynie na działanie drugiego. A co ważniejsze oba skrypty muszą być przenoszone razem, ponieważ stanowią komponenty niezbędne do działania całego skryptu. Ta zewnętrzna zależność może stać się przyczyną trudnych do zdiagnozowania problemów, w szczególności gdy nie zdajemy sobie z niej sprawy.

Jedna z metod, które ułatwiają rozwiązywanie tego typu problemów, polega na wykorzystaniu cmdletu Test-Path do sprawdzania, czy dołączany plik istnieje. W przypadku braku pliku możemy wygenerować odpowiedni komunikat. Takie podejście umożliwia sygnalizowanie braku pliku i ułatwia diagnozowanie źródła problemu. Dlatego Skrypciarze zawsze zalecają stosowanie cmdletu Test-Path w przypadku wykorzystania scenariusza z dołączanym plikiem. Zaprezentowana poniżej, poprawiona wersja skryptu ConvertToFahrenheit_Include2.ps1 demonstruje to podejście:

Param($Celsius)

$includeFile = "c:\data\scriptingGuys\ConversionFunctions.ps1"

if(!(test-path -path $includeFile))

  {

   "Unable to find $includeFile"

   Exit

  }

. $includeFile

ConvertToFahrenheit($Celsius)

Jak można zauważyć, rozwiązanie to zaczyna być nieco absurdalne. Mamy dziewięć linii kodu, który umożliwia wykorzystanie funkcji zawierającej trzy linie. Sami musimy ocenić, czy w danej sytuacji warto zastosować dołączanie pliku. Im bardziej rozbudowany skrypt, tym bardziej odczuwalne stają się korzyści wynikające z wykorzystania dołączanego pliku, takie jak uproszczony i skrócony kod. W skrypcie ConvertUseFunctions.ps1 tworzymy funkcję o nazwie ParseAction, która analizuje wartości action oraz value dostarczane w wierszu polecenia, a następnie wywołuje odpowiednią funkcję. Skrypt ConvertUseFunctions.ps1 został zaprezentowany poniżej:

Param($action,$value,[switch]$help)

Function GetHelp()

{

  if($help)

  {

   "choose conversion: M(eters), F(eet) C(elsius),Fa(renheit),Mi(les),K(ilometers) and value"

   " Convert -a M -v 10 converts 10 meters to feet."

  } #end if help

} #end getHelp

Function GetInclude()

{

 $includeFile = "c:\data\scriptingGuys\ConversionFunctions.ps1"

 if(!(test-path -path $includeFile))

   {

    "Unable to find $includeFile"

    Exit

   }

. $includeFile

} #end GetInclude

Function ParseAction()

{ 

 switch ($action)

 {

  "M" { ConvertToFeet($value) }

  "F"  { ConvertToMeters($value) }

  "C" { ConvertToFahrenheit($value) }

  "Fa" { ConvertToCelsius($value) }

  "Mi" { ConvertToKilometers($value) }

  "K"  { ConvertToMiles($value) }

  DEFAULT { "Dude illegal value." ; GetHelp ; exit }

 } #end action

} #end ParseAction

# *** Początek skryptu ***

If($help) { GetHelp ; exit }

if(!$action) { "Missing action" ; GetHelp ; exit }

GetInclude

ParseAction

Jednak należy podkreślić, że musieliśmy dokonać modyfikacji dołączanego pliku. Ponieważ ładujemy funkcje pomocnicze z poziomu innej funkcji, zasięg funkcji pomocniczych jest domyślnie ograniczony do tej funkcji i nie są one dostępne w innych funkcjach. Aby uniknąć problemów z dziedziczeniem, dodaliśmy znacznik script do każdej tworzonej funkcji. Ten znacznik script został zaprezentowany poniżej:

Function Script:ConvertToMeters($feet)

{

  "$feet feet equals $($feet*.31) meters"

} #end ConvertToMeters

Mam nadzieję, że powyższy artykuł rozjaśnia kwestię wielokrotnego wykorzystywania kodu w skryptach. I pamiętajcie, że recycling nie ogranicza się tylko do surowców wtórnych.

Ed Wilson i Craig Liebendorfer, Skrypciarze

 Do początku strony Do początku strony

Centrum skryptów - Systemy operacyjne