Wszystko, co kiedykolwiek chciałeś wiedzieć o instrukcji switch
Podobnie jak w przypadku wielu innych języków program PowerShell ma polecenia służące do kontrolowania przepływu wykonywania w skryptach. Jedną z tych instrukcji jest instrukcja switch i w programie PowerShell oferuje funkcje, które nie znajdują się w innych językach. Obecnie szczegółowo omówimy pracę z programem PowerShell switch
.
Uwaga
Oryginalna wersja tego artykułu pojawiła się na blogu napisanym przez @KevinMarquette. Zespół programu PowerShell dziękuje Kevinowi za udostępnienie tej zawartości nam. Zapoznaj się ze swoim blogiem na PowerShellExplained.com.
Instrukcja if
Jedną z pierwszych instrukcji, które poznasz, jest if
instrukcja . Umożliwia wykonanie bloku skryptu, jeśli instrukcja to $true
.
if ( Test-Path $Path )
{
Remove-Item $Path
}
Można mieć znacznie bardziej skomplikowaną logikę przy użyciu instrukcji elseif
i .else
Oto przykład, w którym mam wartość liczbową dla dnia tygodnia i chcę uzyskać nazwę jako ciąg.
$day = 3
if ( $day -eq 0 ) { $result = 'Sunday' }
elseif ( $day -eq 1 ) { $result = 'Monday' }
elseif ( $day -eq 2 ) { $result = 'Tuesday' }
elseif ( $day -eq 3 ) { $result = 'Wednesday' }
elseif ( $day -eq 4 ) { $result = 'Thursday' }
elseif ( $day -eq 5 ) { $result = 'Friday' }
elseif ( $day -eq 6 ) { $result = 'Saturday' }
$result
Wednesday
Okazuje się, że jest to typowy wzorzec i istnieje wiele sposobów radzenia sobie z tym. Jeden z nich ma wartość switch
.
Switch, instrukcja
Instrukcja switch
umożliwia podanie zmiennej i listy możliwych wartości. Jeśli wartość jest zgodna ze zmienną, zostanie wykonany jej skryptblock.
$day = 3
switch ( $day )
{
0 { $result = 'Sunday' }
1 { $result = 'Monday' }
2 { $result = 'Tuesday' }
3 { $result = 'Wednesday' }
4 { $result = 'Thursday' }
5 { $result = 'Friday' }
6 { $result = 'Saturday' }
}
$result
'Wednesday'
W tym przykładzie wartość $day
jest zgodna z jedną z wartości liczbowych, a następnie jest przypisana prawidłowa nazwa do $result
. W tym przykładzie wykonujemy tylko przypisanie zmiennych, ale w tych blokach skryptu można wykonać dowolny program PowerShell.
Przypisywanie do zmiennej
Możemy napisać ten ostatni przykład w inny sposób.
$result = switch ( $day )
{
0 { 'Sunday' }
1 { 'Monday' }
2 { 'Tuesday' }
3 { 'Wednesday' }
4 { 'Thursday' }
5 { 'Friday' }
6 { 'Saturday' }
}
Umieszczamy wartość w potoku programu PowerShell i przypisujemy ją do elementu $result
. Możesz to zrobić za pomocą instrukcji if
i foreach
.
Wartość domyślna
Możemy użyć słowa kluczowego default
, aby zidentyfikować, co powinno się zdarzyć, jeśli nie ma dopasowania.
$result = switch ( $day )
{
0 { 'Sunday' }
# ...
6 { 'Saturday' }
default { 'Unknown' }
}
W tym miejscu zwracamy wartość Unknown
w przypadku domyślnym.
Ciągi
W tych ostatnich przykładach pasowałem do liczb, ale można również dopasować ciągi.
$item = 'Role'
switch ( $item )
{
Component
{
'is a component'
}
Role
{
'is a role'
}
Location
{
'is a location'
}
}
is a role
Postanowiłem nie opakowować Component
elementu iRole
Location
dopasować w cudzysłowie tutaj, aby podkreślić, że są opcjonalne. W większości przypadków element switch
traktuje te jako ciąg.
Tablice
Jedną z chłodnych funkcji programu PowerShell switch
jest sposób obsługi tablic. Jeśli nadasz tablicy switch
, przetwarza każdy element w tej kolekcji.
$roles = @('WEB','Database')
switch ( $roles ) {
'Database' { 'Configure SQL' }
'WEB' { 'Configure IIS' }
'FileServer' { 'Configure Share' }
}
Configure IIS
Configure SQL
Jeśli elementy tablicy są powtarzane, są one dopasowywane wiele razy przez odpowiednią sekcję.
PsItem
Możesz użyć elementu $PSItem
lub $_
, aby odwołać się do bieżącego przetworzonego elementu. Gdy wykonamy proste dopasowanie, $PSItem
to wartość, którą dopasowujemy. Będę wykonywać kilka zaawansowanych dopasowań w następnej sekcji, w której jest używana ta zmienna.
Parametry
Unikatową funkcją programu PowerShell switch
jest to, że ma ona wiele parametrów przełącznika, które zmieniają sposób jego działania.
-Casesensitive
Dopasowania nie są domyślnie uwzględniane w wielkości liter. Jeśli musisz mieć wielkość liter, możesz użyć polecenia -CaseSensitive
. Może to być używane w połączeniu z innymi parametrami przełącznika.
-Symbol wieloznaczny
Możemy włączyć obsługę symboli wieloznacznych za pomocą przełącznika -wildcard
. Używa to tej samej logiki wieloznacznych co -like
operator do wykonania każdego dopasowania.
$Message = 'Warning, out of disk space'
switch -Wildcard ( $message )
{
'Error*'
{
Write-Error -Message $Message
}
'Warning*'
{
Write-Warning -Message $Message
}
default
{
Write-Information $message
}
}
WARNING: Warning, out of disk space
W tym miejscu przetwarzamy komunikat, a następnie generujemy go na różnych strumieniach na podstawie zawartości.
-Regex
Instrukcja switch obsługuje wyrażenia regularne, podobnie jak w przypadku symboli wieloznacznych.
switch -Regex ( $message )
{
'^Error'
{
Write-Error -Message $Message
}
'^Warning'
{
Write-Warning -Message $Message
}
default
{
Write-Information $message
}
}
Mam więcej przykładów używania wyrażenia regularnego w innym artykule napisałem: Wiele sposobów używania wyrażenia regularnego.
-Plik
Mało znaną funkcją instrukcji switch jest to, że może przetworzyć plik za pomocą parametru -File
. Używasz -file
ścieżki do pliku zamiast nadawać mu wyrażenie zmiennej.
switch -Wildcard -File $path
{
'Error*'
{
Write-Error -Message $PSItem
}
'Warning*'
{
Write-Warning -Message $PSItem
}
default
{
Write-Output $PSItem
}
}
Działa tak samo jak przetwarzanie tablicy. W tym przykładzie połączę go z dopasowaniem symboli wieloznacznych i użyjemy elementu $PSItem
. Spowoduje to przetworzenie pliku dziennika i przekonwertowanie go na komunikaty ostrzegawcze i komunikaty o błędach w zależności od dopasowań wyrażeń regularnych.
Szczegóły zaawansowane
Teraz, gdy znasz wszystkie te udokumentowane funkcje, możemy ich używać w kontekście bardziej zaawansowanego przetwarzania.
Wyrażenia
Element switch
może znajdować się w wyrażeniu zamiast zmiennej.
switch ( ( Get-Service | Where status -eq 'running' ).name ) {...}
Niezależnie od tego, jakie wyrażenie daje w ocenie, jest wartość użyta dla dopasowania.
Wiele dopasowań
Być może została już odebrana, ale może być zgodna z switch
wieloma warunkami. Jest to szczególnie prawdziwe w przypadku używania -wildcard
lub -regex
dopasowania. Ten sam warunek można dodać wiele razy i wszystkie są wyzwalane.
switch ( 'Word' )
{
'word' { 'lower case word match' }
'Word' { 'mixed case word match' }
'WORD' { 'upper case word match' }
}
lower case word match
mixed case word match
upper case word match
Wszystkie trzy z tych instrukcji są wyzwalane. Pokazuje to, że każdy warunek jest sprawdzany (w kolejności). Dotyczy to przetwarzania tablic, w których każdy element sprawdza każdy warunek.
Kontynuuj
Zwykle jest to miejsce, w którym wprowadzałbym break
oświadczenie, ale lepiej jest nauczyć się używać continue
najpierw. Podobnie jak w przypadku foreach
pętli, continue
kontynuuje na następnym elemencie w kolekcji lub kończy switch
działanie, jeśli nie ma więcej elementów. Możemy ponownie napisać ten ostatni przykład z instrukcjami continue, aby wykonać tylko jedną instrukcję.
switch ( 'Word' )
{
'word'
{
'lower case word match'
continue
}
'Word'
{
'mixed case word match'
continue
}
'WORD'
{
'upper case word match'
continue
}
}
lower case word match
Zamiast dopasowywać wszystkie trzy elementy, pierwszy z nich jest zgodny, a przełącznik kontynuuje następną wartość. Ponieważ nie ma wartości do przetworzenia, przełącznik kończy działanie. W następnym przykładzie pokazano, jak symbol wieloznaczny może być zgodny z wieloma elementami.
switch -Wildcard -File $path
{
'*Error*'
{
Write-Error -Message $PSItem
continue
}
'*Warning*'
{
Write-Warning -Message $PSItem
continue
}
default
{
Write-Output $PSItem
}
}
Ponieważ wiersz w pliku wejściowym może zawierać zarówno słowo Error
, jak i Warning
, chcemy tylko, aby pierwszy wiersz został wykonany, a następnie kontynuować przetwarzanie pliku.
Przerwa
Instrukcja break
zamyka przełącznik. Jest to to samo zachowanie, które continue
przedstawia pojedyncze wartości. Różnica jest wyświetlana podczas przetwarzania tablicy. break
zatrzymuje wszystkie operacje przetwarzania w przełączniku i continue
przechodzi do następnego elementu.
$Messages = @(
'Downloading update'
'Ran into errors downloading file'
'Error: out of disk space'
'Sending email'
'...'
)
switch -Wildcard ($Messages)
{
'Error*'
{
Write-Error -Message $PSItem
break
}
'*Error*'
{
Write-Warning -Message $PSItem
continue
}
'*Warning*'
{
Write-Warning -Message $PSItem
continue
}
default
{
Write-Output $PSItem
}
}
Downloading update
WARNING: Ran into errors downloading file
write-error -message $PSItem : Error: out of disk space
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException
W takim przypadku, jeśli trafimy na jakiekolwiek wiersze rozpoczynające się od Error
, zostanie wyświetlony błąd i przełącznik zostanie zatrzymany.
To właśnie break
to stwierdzenie robi dla nas. Jeśli znajdziemy Error
wewnątrz ciągu, a nie tylko na początku, napiszemy go jako ostrzeżenie. Robimy to samo dla Warning
. Możliwe, że wiersz może zawierać zarówno słowo Error
, jak i Warning
, ale potrzebujemy tylko jednego do przetworzenia. To jest to, co continue
robi dla nas oświadczenie.
Podział etykiet
Instrukcja switch
obsługuje break/continue
etykiety tak samo jak foreach
.
:filelist foreach($path in $logs)
{
:logFile switch -Wildcard -File $path
{
'Error*'
{
Write-Error -Message $PSItem
break filelist
}
'Warning*'
{
Write-Error -Message $PSItem
break logFile
}
default
{
Write-Output $PSItem
}
}
}
Osobiście nie lubię używania etykiet break, ale chciałem je wskazać, ponieważ są one mylące, jeśli nigdy wcześniej ich nie widziałeś. Jeśli masz wiele switch
instrukcji lub foreach
, które są zagnieżdżone, możesz chcieć wydzielić więcej niż wewnętrzny najbardziej element. Możesz umieścić etykietę na obiekcie switch
, która może być elementem docelowym obiektu break
.
Wyliczenie
Program PowerShell 5.0 dał nam wyliczenia i możemy użyć ich w przełączniku.
enum Context {
Component
Role
Location
}
$item = [Context]::Role
switch ( $item )
{
Component
{
'is a component'
}
Role
{
'is a role'
}
Location
{
'is a location'
}
}
is a role
Jeśli chcesz zachować wszystko tak mocno typizowane wyliczenia, możesz umieścić je w nawiasach.
switch ($item )
{
([Context]::Component)
{
'is a component'
}
([Context]::Role)
{
'is a role'
}
([Context]::Location)
{
'is a location'
}
}
Nawiasy są potrzebne w tym miejscu, aby przełącznik nie traktować wartości [Context]::Location
jako ciągu literału.
ScriptBlock
W razie potrzeby możemy użyć blokady skryptu, aby przeprowadzić ocenę dopasowania.
$age = 37
switch ( $age )
{
{$PSItem -le 18}
{
'child'
}
{$PSItem -gt 18}
{
'adult'
}
}
'adult'
To zwiększa złożoność i może utrudnić switch
czytanie. W większości przypadków, w których należy użyć czegoś takiego, lepiej byłoby użyć if
instrukcji i elseif
. Rozważę użycie tego, gdybym miał już duży przełącznik i potrzebowałem dwóch elementów, aby trafić w ten sam blok oceny.
Jedną z rzeczy, które myślę, że pomaga w czytelności jest umieszczenie scriptblock w nawiasach.
switch ( $age )
{
({$PSItem -le 18})
{
'child'
}
({$PSItem -gt 18})
{
'adult'
}
}
Nadal wykonuje to samo działanie i daje lepszą przerwę wizualną podczas szybkiego przeglądania.
$matches wyrażeń regularnych
Musimy ponownie zwrócić się do regex, aby dotknąć czegoś, co nie jest natychmiast oczywiste. Użycie wyrażenia regularnego wypełnia zmienną $matches
. Idę do użycia $matches
więcej, kiedy mówię o wielu sposobach korzystania z regex. Oto szybki przykład pokazujący go w akcji z nazwanymi dopasowaniami.
$message = 'my ssn is 123-23-3456 and credit card: 1234-5678-1234-5678'
switch -regex ($message)
{
'(?<SSN>\d\d\d-\d\d-\d\d\d\d)'
{
Write-Warning "message contains a SSN: $($matches.SSN)"
}
'(?<CC>\d\d\d\d-\d\d\d\d-\d\d\d\d-\d\d\d\d)'
{
Write-Warning "message contains a credit card number: $($matches.CC)"
}
'(?<Phone>\d\d\d-\d\d\d-\d\d\d\d)'
{
Write-Warning "message contains a phone number: $($matches.Phone)"
}
}
WARNING: message may contain a SSN: 123-23-3456
WARNING: message may contain a credit card number: 1234-5678-1234-5678
$null
Możesz dopasować $null
wartość, która nie musi być wartością domyślną.
$values = '', 5, $null
switch ( $values )
{
$null { "Value '$_' is `$null" }
{ '' -eq $_ } { "Value '$_' is an empty string" }
default { "Value [$_] isn't an empty string or `$null" }
}
Value '' is an empty string
Value [5] isn't an empty string or $null
Value '' is $null
Podczas testowania pustego ciągu w switch
instrukcji ważne jest użycie instrukcji porównania, jak pokazano w tym przykładzie zamiast wartości ''
pierwotnej . W instrukcji switch
wartość ''
nieprzetworzona jest również zgodna $null
z wartością . Na przykład:
$values = '', 5, $null
switch ( $values )
{
$null { "Value '$_' is `$null" }
'' { "Value '$_' is an empty string" }
default { "Value [$_] isn't an empty string or `$null" }
}
Value '' is an empty string
Value [5] isn't an empty string or $null
Value '' is $null
Value '' is an empty string
Ponadto należy zachować ostrożność przy użyciu pustych zwrotów z poleceń cmdlet. Polecenia cmdlet lub potoki, które nie mają danych wyjściowych, są traktowane jako pusta tablica, która nie pasuje do niczego, w tym przypadku default
.
$file = Get-ChildItem NonExistantFile*
switch ( $file )
{
$null { '$file is $null' }
default { "`$file is type $($file.GetType().Name)" }
}
# No matches
Wyrażenie stałe
Lee Dailey zwrócił uwagę, że możemy użyć wyrażenia stałego $true
do oceny [bool]
elementów.
Wyobraź sobie, że mamy kilka testów logicznych, które muszą się zdarzyć.
$isVisible = $false
$isEnabled = $true
$isSecure = $true
switch ( $true )
{
$isEnabled
{
'Do-Action'
}
$isVisible
{
'Show-Animation'
}
$isSecure
{
'Enable-AdminMenu'
}
}
Do-Action
Enabled-AdminMenu
Jest to czysty sposób oceniania i podejmowania działań na temat stanu kilku pól logicznych. Fajną rzeczą w tym jest to, że można mieć jeden mecz przerzucić stan wartości, która nie została jeszcze obliczona.
$isVisible = $false
$isEnabled = $true
$isAdmin = $false
switch ( $true )
{
$isEnabled
{
'Do-Action'
$isVisible = $true
}
$isVisible
{
'Show-Animation'
}
$isAdmin
{
'Enable-AdminMenu'
}
}
Do-Action
Show-Animation
Ustawienie $isEnabled
na $true
wartość w tym przykładzie gwarantuje również, że $isVisible
ustawiono $true
wartość .
Następnie po $isVisible
obliczeniu zostanie wywołany jego blok skryptu. Jest to nieco odwrotnie intuicyjne, ale jest sprytnym zastosowaniem mechaniki.
$switch zmienną automatyczną
Gdy obiekt switch
przetwarza jego wartości, tworzy moduł wyliczający i wywołuje go $switch
. Jest to zmienna automatyczna utworzona przez program PowerShell i można nią manipulować bezpośrednio.
$a = 1, 2, 3, 4
switch($a) {
1 { [void]$switch.MoveNext(); $switch.Current }
3 { [void]$switch.MoveNext(); $switch.Current }
}
Daje to wyniki:
2
4
Przenosząc moduł wyliczający do przodu, następny element nie jest przetwarzany przez switch
element , ale możesz uzyskać bezpośredni dostęp do tej wartości. Nazwałbym to szaleństwem.
Inne wzorce
Tabele skrótów
Jednym z moich najpopularniejszych postów jest ten, który zrobiłem na tabelach skrótów. Jednym z przypadków użycia elementu hashtable
jest tabela odnośników. Jest to alternatywne podejście do wspólnego wzorca, którego switch
często dotyczy instrukcja.
$day = 3
$lookup = @{
0 = 'Sunday'
1 = 'Monday'
2 = 'Tuesday'
3 = 'Wednesday'
4 = 'Thursday'
5 = 'Friday'
6 = 'Saturday'
}
$lookup[$day]
Wednesday
Jeśli używam switch
tylko elementu jako odnośnika, często używam elementu hashtable
.
Wyliczenie
Program PowerShell 5.0 wprowadził Enum
funkcję i jest również opcją w tym przypadku.
$day = 3
enum DayOfTheWeek {
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
}
[DayOfTheWeek]$day
Wednesday
Moglibyśmy przejść przez cały dzień, patrząc na różne sposoby rozwiązania tego problemu. Chciałem tylko upewnić się, że wiesz, że masz opcje.
Końcowe wyrazy
Instrukcja switch jest prosta na powierzchni, ale oferuje niektóre zaawansowane funkcje, które większość ludzi nie zdaje sobie sprawy, są dostępne. Łączenie tych funkcji sprawia, że jest to zaawansowana funkcja. Mam nadzieję, że nauczyłeś się czegoś, czego wcześniej nie zdałeś sobie sprawy.
Opinia
https://aka.ms/ContentUserFeedback.
Dostępne już wkrótce: W 2024 r. będziemy stopniowo wycofywać zgłoszenia z serwisu GitHub jako mechanizm przesyłania opinii na temat zawartości i zastępować go nowym systemem opinii. Aby uzyskać więcej informacji, sprawdź:Prześlij i wyświetl opinię dla