Kończenie skryptu w PowerShell


394

Szukałem sposobu na zakończenie skryptu PowerShell (PS1), gdy wystąpi niemożliwy do naprawienia błąd w funkcji. Na przykład:

function foo() {
    # Do stuff that causes an error
    $host.Exit()
}

Oczywiście nie ma czegoś takiego jak $host.Exit(). Jest $host.SetShouldExit(), ale tak naprawdę zamyka okno konsoli, czego nie chcę. Potrzebuję czegoś równoważnego do Pythona, sys.exit()które po prostu zatrzyma wykonanie bieżącego skryptu bez dalszego adieu.

Edycja: Tak, to tylko exit. Duh.


8
Jeśli chcesz uniknąć zamykania okna PowerShell lub ISE w moim przypadku; zamiast tego użyj „return”. To po prostu kończy bieżący kontekst działania. „Nowy facet” dokładnie wyjaśnia wszystkie opcje do celów edukacyjnych; możesz rozważyć zmianę zaakceptowanej odpowiedzi (obecnie i tak ma więcej głosów) dla przyszłych użytkowników StackOverflow. Umożliwi to również debugowanie skryptu.
— ZaxLofful

Odpowiedzi:


389

Należy użyć do exitsłowa kluczowego .


15
Cholera jasna, gdybym nie był tak przyłapany na próbowaniu wymyślenia, jak zrobić te rzeczy sprytnie, prawdopodobnie spróbowałbym tego na początku i doszedł do wniosku, że to działa :) Dzięki.
— kprobst

118
Jak to jest akceptowana odpowiedź? W szczególności „zamyka okno konsoli”, które pytający powiedział „co nie jest tym, czego chcę”.
— claudekennilol

3
@claudekennilol Tylko pytający może zaakceptować odpowiedź. Albo przeoczyli fakt, że wyjście ma zamknąć okno, albo zmienili zdanie i uznali to za dopuszczalne.
— Iszi

3
Nie zamyka okna konsoli w v3 lub v4, których używam. Cóż, zrobi to, jeśli uruchomisz skrypt z Eksploratora, ale bez względu na to, jak zakończysz skrypt, zrobi to. Jeśli działa z okna poleceń PowerShell, nie zamyka okna.
— Joshua Nurczyk

14
Odpowiedź New Guya jest o wiele dokładniejsza i dezerterzy są oznaczani jako zaakceptowani.
— Jim Aho

585

Zdaję sobie sprawę, że to stary post, ale często wracam do tego wątku, ponieważ jest to jeden z najlepszych wyników wyszukiwania podczas wyszukiwania tego tematu. Jednak zawsze zostaję bardziej zdezorientowany niż wtedy, gdy przybyłem z powodu sprzecznych informacji. Ostatecznie zawsze muszę przeprowadzić własne testy, aby to rozgryźć. Więc tym razem opublikuję swoje wyniki.

TL; DR Większość osób będzie chciała użyć Exitdo zakończenia uruchomionych skryptów. Jeśli jednak twój skrypt jedynie deklaruje funkcje do późniejszego użycia w powłoce, będziesz chciał użyć ich Returnw definicjach tych funkcji.

Wyjście vs powrót vs przerwa

  • Wyjdź: spowoduje to „wyjście” z aktualnie uruchomionego kontekstu. Wywołanie tego polecenia ze skryptu spowoduje jego zamknięcie. Jeśli wywołasz to polecenie z powłoki, opuści powłokę.

    Jeśli funkcja wywoła polecenie Exit, wyjdzie z dowolnego kontekstu, w którym działa. Jeśli więc funkcja ta zostanie wywołana tylko z działającego skryptu, zakończy działanie tego skryptu. Jeśli jednak skrypt po prostu deklaruje funkcję, aby można jej było użyć z bieżącej powłoki, a ty uruchomisz tę funkcję z powłoki, opuści powłokę, ponieważ powłoka jest kontekstem, w którym działa funkcja obsługująca Exitpolecenie.

    Uwaga: Domyślnie, jeśli klikniesz skrypt prawym przyciskiem myszy, aby uruchomić go w programie PowerShell, po zakończeniu działania skryptu program PowerShell zamknie się automatycznie. Nie ma to nic wspólnego z Exitpoleceniem ani czymkolwiek innym w twoim skrypcie. Jest to tylko domyślne zachowanie programu PowerShell dla skryptów uruchamianych przy użyciu tej konkretnej metody uruchamiania skryptu. To samo dotyczy plików wsadowych i okna wiersza poleceń.

  • Powrót: Powróci do poprzedniego punktu wywoławczego. Jeśli wywołasz to polecenie ze skryptu (poza funkcjami), powróci ono do powłoki. Jeśli wywołasz to polecenie z powłoki, powróci ono do powłoki (która jest poprzednim punktem wywoławczym dla pojedynczego polecenia uruchamianego z powłoki). Wywołanie tego polecenia z funkcji spowoduje powrót do miejsca, z którego funkcja została wywołana.

    Wykonanie wszelkich poleceń po punkcie połączenia, do którego jest zwracany, będzie kontynuowane od tego miejsca. Jeśli skrypt jest wywoływany z powłoki i zawiera Returnpolecenie poza funkcjami, to po powrocie do powłoki nie ma więcej poleceń do uruchomienia, dzięki czemu Returnużywany jest w ten sam sposób jak Exit.

  • Przerwa: spowoduje to wyrwanie się z pętli i zmianę przypadków. Wywołanie tego polecenia, gdy nie jest ono w pętli lub zmieniono wielkość liter, spowoduje wyrwanie się ze skryptu. Jeśli wywołujesz Breakwewnątrz pętli zagnieżdżonej w pętli, wyłamie się ona tylko z pętli, w której została wywołana.

    Istnieje również interesująca funkcja Break której można poprzedzić pętlę etykietą, a następnie wyjść z tej pętli z etykietą, nawet jeśli Breakpolecenie jest wywoływane w kilku zagnieżdżonych grupach w tej pętli z etykietą.

    While ($true) {
        # Code here will run
    
        :myLabel While ($true) {
            # Code here will run
    
            While ($true) {
                # Code here will run
    
                While ($true) {
                    # Code here will run
                    Break myLabel
                    # Code here will not run
                }
    
                # Code here will not run
            }
    
            # Code here will not run
        }
    
        # Code here will run
    }

39
Warto również zauważyć, że Exitmożna przyjąć kod powrotu jako parametr (domyślnie 0) - np Exit 3.
— aucuparia,

2
Zgadzam się, to jest o wiele lepsza odpowiedź. „Przerwa” może mieć niezamierzone konsekwencje.
— iagomartinez

Nie jestem pewien, czy Twój komentarz na temat „Wyjdź” jest całkowicie poprawny, chociaż ogólnie jest to świetna odpowiedź. Wyjście wydaje się powodować zamknięcie ISE w sposób, w jaki wydaje się, że nic innego się nie dzieje. Samo wyjście z kontekstu (na przykład ukończenie skryptu) tego nie robi.
— Bill K,

1
@BillK Rzeczywiście. Zaktualizowałem odpowiedź. Kiedy pisałem to po raz pierwszy, nie pamiętam, aby znaleźć oficjalną dokumentację dotyczącą Exit. Zrobiłem wtedy Get-Command Exiti Get-Alias Exitbez rezultatów. Następnie sprawdziłem, czy jest to słowo kluczowe, i nie znalazłem na nim oficjalnej dokumentacji. Patrząc na to teraz, nie wiem jednak, jak doszedłem do tego wniosku. Oczywiście jest to słowo kluczowe ( technet.microsoft.com/en-us/library/hh847744.aspx ). Być może dlatego, że Exit jest jednym z niewielu słów kluczowych, które nie mają własnego tematu about_ help, dlatego też lista tematów na lewym pasku bocznym go nie zawierała.
— Nowy facet

6
Co z rzutem?
— JDC

80

Exitzamknie również PowerShell. Jeśli chcesz „zerwać” z bieżącej funkcji lub skryptu - użyj Break:)

If ($Breakout -eq $true)
{
     Write-Host "Break Out!"
     Break
}
ElseIf ($Breakout -eq $false)
{
     Write-Host "No Breakout for you!"
}
Else
{
    Write-Host "Breakout wasn't defined..."
}

5
Nie używaj, breakjeśli chcesz po prostu wyjść z bieżącej funkcji ... skrypty wywoływania również mogą zostać zakłócone!
— DannyMeister

49

Błąd zapisu dotyczy błędów nie kończących się, a błąd rzucania błędów

Polecenie cmdlet Write-Error deklaruje błąd nie kończący się. Domyślnie błędy są przesyłane w strumieniu błędów do wyświetlanego programu hosta wraz z danymi wyjściowymi.

Błędy nie kończące się zapisują błąd do strumienia błędów, ale nie przerywają przetwarzania poleceń. Jeśli zadeklarowany zostanie błąd nie kończący się na jednym elemencie w kolekcji elementów wejściowych, polecenie kontynuuje przetwarzanie pozostałych elementów w kolekcji.

Aby zgłosić błąd zakończenia, użyj słowa kluczowego Rzut. Aby uzyskać więcej informacji, zobacz about_Throw ( http://go.microsoft.com/fwlink/?LinkID=145153 ).


4
To wydaje się najbardziej prawidłowym sposobem zakończenia działania z błędem. Deleguje na osobę dzwoniącą próbę obsłużenia błędu, co jest znacznie lepsze niż po prostu próba nagłego zakończenia.
— Paul Turner

Dla mnie, przynajmniej w funkcjach modułu, wyrzucaj wyjścia, ale nie ustawiam kodu wyjścia. Zostało to wykonane przez CLI np powershell -command "& module-function ...". Musiałem przekonwertować te funkcje, aby rzucić do owijającego try-catch i wyjść z tego owijającego catch, aby faktycznie wyprowadzić kod wyjścia błędu.
— Josh

2
Nie zapomnij $PSCmdlet.ThrowTerminatingError()o przypadkach, gdy rzut nie może wykonać zadania (znany problem bez błędów kończących od throw)
— Djarid

33

Kończy ten proces i nadaje bazowemu systemowi operacyjnemu określony kod wyjścia.

https://msdn.microsoft.com/en-us/library/system.environment.exit%28v=vs.110%29.aspx

[Environment]::Exit(1)

Umożliwi to wyjście z określonym kodem wyjścia, który można odebrać od dzwoniącego.


3
W PowerShell możesz po prostu użyć do tego wbudowanego wyjścia, np Exit 1.
— Jonas,

3
wbudowane wyjście nie zawsze będzie działać zgodnie z oczekiwaniami. Spróbuj tego w PowerShell: „Exit 5”> test1.ps1 powershell.exe. \ Test1.ps1 $ lastexitcode „[Środowisko] :: Exit (5)”> test2.ps1 powershell.exe. \ Test2.ps1 $ lastexitcode
— gabriwinter

1
[Environment]::Exit(1)ma efekt uboczny wychodzenia z mojego okna PowerShell, gdy wywołuję go w skrypcie, ponieważ używanie exitgo nie wydaje się robić.
— Josh Desmond

25

Myślę, że Returnzamiast tego szukasz Break. Przerwa jest zwykle używana w przypadku pętli i przerywa tylko od najbardziej wewnętrznego bloku kodu. Użyj Return, aby wyjść z funkcji lub skryptu.


7
To nie jest poprawne - OP konkretnie prosi o wyjście ze skryptu z funkcji . Returnpo prostu powróci z funkcji, a nie ze skryptu. ( Returnna najwyższym poziomie skryptu skrypt zostanie zakończony, ale to nie było pytanie.)
— Michael Sorens,

1
czy ta „odpowiedź” faktycznie komentuje odpowiedź EverydayNerd?
— tkokasih

22

Zgłoszenie wyjątku będzie dobre, szczególnie jeśli chcesz wyjaśnić przyczynę błędu:

throw "Error Message"

Spowoduje to wygenerowanie błędu zakończenia.


3
Nie sądzę, żeby to dodało więcej niż odpowiedź Grega Braya prawie rok wcześniej stackoverflow.com/a/20556550/695671
— Jason S

12

Być może lepiej jest użyć „pułapki”. Pułapka programu PowerShell określa blok kodu do uruchomienia, gdy wystąpi błąd lub błąd. Rodzaj

Get-Help about_trap

aby dowiedzieć się więcej o instrukcji pułapki.


10

Przypadkowo odkryłem, że (np. Po prostu tam , gdzie etykieta nie istnieje ) wydaje się, że wyłamuje się z całego skryptu (nawet z funkcji) i utrzymuje hosta przy życiu. W ten sposób możesz stworzyć funkcję, która łamie skrypt z dowolnego miejsca (np. Pętla rekurencyjna) bez znajomości bieżącego zakresu (i tworzenia etykiet):Break <UnknownLabel>Break ScriptScript

Function Quit($Text) {
    Write-Host "Quiting because: " $Text
    Break Script
} 

1
Twoja odpowiedź jest prawdziwa, ale pamiętaj, że może to powodować problemy dla osób wywołujących skrypt, jeśli nie zgadzają się z twoją chęcią wyjścia z całego skryptu: stackoverflow.com/questions/45746588/...
— DannyMeister

5

Użyłem tego do ponownego uruchomienia programu. Nie wiem, czy to by pomogło, ale jest to prosta instrukcja if wymagająca tylko dwóch różnych wpisów. Dla mnie działało to w PowerShell.

$rerun = Read-Host "Rerun report (y/n)?"

if($rerun -eq "y") { Show-MemoryReport }
if($rerun -eq "n") { Exit }

Nie wiem, czy to pomaga, ale wierzę, że byłoby to zgodne z zakończeniem programu po jego uruchomieniu. Jednak w tym przypadku każde zdefiniowane wejście wymaga wyszczególnionego i skategoryzowanego wyniku. Możesz również poprosić exit o wywołanie nowego wiersza polecenia i zakończenie programu w ten sposób.

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.