Завершення сценарію в PowerShell


394

Я шукав спосіб припинити скрипт PowerShell (PS1), коли в функції виникає непоправна помилка. Наприклад:

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

Звичайно, такого немає $host.Exit(). Є $host.SetShouldExit(), але це фактично закриває вікно консолі, а це не те, що я хочу. Мені потрібно щось еквівалентне Python, sys.exit()що просто зупинить виконання поточного сценарію без додаткових зусиль.

Редагувати: Так, це просто exit. Дух.


8
Якщо ви хочете уникнути закриття вікна PowerShell або ISE в моєму випадку; використовувати замість "return". Це просто закінчує поточний контекст запуску. "Новий хлопець" ретельно пояснює всі варіанти навчальних цілей; ви можете подумати про зміну прийнятої відповіді (на даний момент набрав більше голосів) для майбутніх користувачів StackOverflow. Це дозволить також налагодити сценарій.
— ZaxLofful

Чи відповідає це на ваше запитання? Що саме таке "вихід" в PowerShell?
— Марк Шультейс

Відповіді:


389

Ви повинні використовувати в exitключове слово .


15
Святе дерьмо, якби мене не так наздогнали, намагаючись розібратися, як це робити розумно, я б, мабуть, спробував це для початку і зрозумів, що це працює :) Дякую.
— kprobst

118
Як це прийнята відповідь? Це спеціально "закриває вікно консолі", яке запитувач сказав: "Це не те, що я хочу".
— claudekennilol

3
@claudekennilol Відповісти може прийняти лише той, хто ставить запитання. Або вони пропустили той факт, що вихід повинен закрити вікно, або вони передумали і вважали прийнятним для своєї мети.
— Іссі

3
Він не закриває вікно консолі в v3 або v4, яке я використовую. Що ж, це буде, якщо запустити скрипт від провідника, але як би ви не закінчили сценарій, це зробить це. Якщо ви працюєте з вікна команди PowerShell, воно не закриває вікно.
— Джошуа Нурчик

14
Відповідь Нового Гая набагато ретельніша, і десерти відзначаються як прийняті.
— Джим Ахо

585

Я розумію, що це стара публікація, але я дуже часто повертаюся до цієї теми, оскільки це один із найкращих результатів пошуку при пошуку цієї теми. Однак я завжди залишаю більше заплутаним, ніж тоді, коли приїхав через конфліктну інформацію. Зрештою, мені завжди доводиться робити власні тести, щоб зрозуміти це. Тож цього разу я опублікую свої висновки.

TL; DR Більшість людей захочуть використовувати Exitдля припинення запущених сценаріїв. Однак якщо ваш скрипт є лише оголошенням функцій, які згодом будуть використані в оболонці, ви хочете використовувати Returnу визначеннях зазначених функцій.

Вихід проти повернення проти перерви

  • Вихід: це "вийде" з поточного контексту. Якщо ви зателефонуєте до цієї команди зі скрипту, вона вийде із сценарію. Якщо ви викликаєте цю команду з оболонки, вона вийде з оболонки.

    Якщо функція викликає команду Exit, вона вийде з будь-якого контексту, в якому вона запущена. Тож якщо ця функція буде викликана тільки з запущеного сценарію, вона вийде з цього сценарію. Однак якщо ваш скрипт просто оголошує функцію, щоб вона могла бути використана з поточної оболонки, і ви запустите цю функцію з оболонки, вона вийде з оболонки, оскільки оболонка - це контекст, в якому виконується функція, що містить Exitкоманду.

    Примітка. Якщо ви натиснете правою кнопкою миші на скрипт, щоб запустити його в PowerShell, після запуску сценарію PowerShell автоматично закриється. Це не має нічого спільного з Exitкомандою або чим-небудь іншим у вашому сценарії. Це просто поведінка PowerShell за замовчуванням для сценаріїв, які виконуються за допомогою цього конкретного методу запуску сценарію. Те саме стосується пакетних файлів та вікна командного рядка.

  • Повернення: Це повернеться до попереднього пункту дзвінка. Якщо ви викликаєте цю команду зі скрипту (поза будь-якими функціями), вона повернеться до оболонки. Якщо ви викликаєте цю команду з оболонки, вона повернеться до оболонки (яка є попередньою точкою виклику для однієї команди, запущеної з оболонки). Якщо ви викликаєте цю команду з функції, вона повернеться туди, куди колись ця функція викликалася.

    Виконання будь-яких команд після точки виклику, до якої вона повертається, триватиме з цієї точки. Якщо скрипт викликається з оболонки, і він містить Returnкоманду поза будь-якими функціями, тоді, коли він повертається до оболонки, більше немає команд для запуску, завдяки чому Returnвикористовуваний таким чином по суті такий же, як Exit.

  • Перерва: це вирветься з циклів і перемикаються випадки. Якщо ви викликаєте цю команду, не перебуваючи в циклі або випадку переключення, вона вийде з сценарію. Якщо ви зателефонуєте Breakвсередину циклу, який вкладений всередині циклу, він вирветься лише з циклу, в який він був викликаний.

    Також є цікава особливість того, Breakде ви можете встановити цикл з міткою, а потім ви можете вийти з цього міченого циклу, навіть якщо Breakкоманда викликається в межах декількох вкладених груп у межах зазначеного циклу.

    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
Також варто зазначити, що Exitможе бути прийнятий код повернення як параметр (за замовчуванням до 0) - наприклад Exit 3.
— аукупарія

2
Я згоден, це набагато краща відповідь. "Перерва" може мати непередбачувані наслідки.
— iagomartinez

Я не впевнений, що ваш коментар про "Вихід" є абсолютно правильним, хоча це загалом чудова відповідь. Схоже, вихід змушує ISE закритись так, що, схоже, нічого іншого не робить. Просто вихід із контексту (наприклад, завершення сценарію) цього не робить.
— Білл К

1
@BillK Дійсно. Я оновив відповідь. Коли я вперше написав це, я пам'ятаю, що не знайшов жодної офіційної документації на Exit. Потім я зробив Get-Command Exitі Get-Alias Exitбез результатів. Потім я подивився, чи це ключове слово, і не знайшов офіційної документації на нього. Однак, дивлячись на це зараз, я не знаю, як я прийшов до цього висновку. Зрозуміло, що це ключове слово ( technet.microsoft.com/en-us/library/hh847744.aspx ). Можливо, тому, що Exit - це одне з єдиних ключових слів, яке не має власної довідкової теми about_, і тому список тем у лівій бічній панелі не містив його.
— Новий хлопець

6
А як же кинути?
— JDC

80

Exitтакож вийде з PowerShell. Якщо ви хочете "вирватися" з лише поточної функції або сценарію - використовуйте 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
Будь ласка, не використовуйте, breakколи ви хочете просто вирватися з поточної функції ... сценарії виклику також можуть бути порушені!
— DannyMeister

49

Помилка запису - це помилки , що не припиняються, а кидок - для припинення помилок

Командлет Write-Error оголошує непомилкову помилку. За замовчуванням помилки надсилаються в потоці помилок до хост-програми, що відображається, разом із висновком.

Нескорочені помилки записують помилку в потік помилок, але вони не припиняють обробку команд. Якщо непомітна помилка оголошена на одному елементі в колекції вхідних елементів, команда продовжує обробляти інші елементи колекції.

Щоб оголосити помилку закінчення, використовуйте ключове слово Throw. Для отримання додаткової інформації див. Про_Throw ( http://go.microsoft.com/fwlink/?LinkID=145153 ).


4
Це видається найбільш правильним способом припинити діяльність з помилкою. Він делегує абоненту, щоб спробувати впоратися з помилкою, що набагато краще, ніж просто намагатися припинити різко.
— Пол Тернер

Для мене, принаймні, в модульних функціях, кидають виходи, але не встановлюють вихідний код. Це було виконано за допомогою CLI, наприклад powershell -command "& module-function ...". Мені потрібно було перетворити ці функції, щоб перекинути його на завершальний спробу виходу та вийти з цього обгорткового улову, щоб фактично вивести код виходу з помилки.
— Джош

2
Не забувайте $PSCmdlet.ThrowTerminatingError()про ті випадки, коли кидок просто не може виконати роботу (відома проблема без жодних кінцевих помилок throw)
— Джарід

33

Припиняє цей процес і надає базовій операційній системі вказаний код виходу.

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

[Environment]::Exit(1)

Це дозволить вам вийти з певним кодом виходу, який можна отримати у абонента.


3
У PowerShell ви можете просто використовувати для цього вбудований Exit, наприклад Exit 1.
— Йонас

3
вбудований вихід не завжди працюватиме так, як ви очікували. Спробуйте це в PowerShell: "Вихід 5"> test1.ps1 powershell.exe \ test1.ps1 $ lastexitcode "[Environment] :: Вихід (5)"> test2.ps1 powershell.exe \ test2.ps1 $ lastexitcode ..
— gabriwinter

1
[Environment]::Exit(1)має побічний ефект від виходу з мого вікна оболонки повноважень, коли я викликаю його в сценарії, де, як користування exit, не здається цього робити.
— Джош Десмонд

25

Я думаю, що ви шукаєте Returnзамість цього Break. Розрив зазвичай використовується для циклів і розривається лише з найпотужнішого кодового блоку. Використовуйте Return для виходу з функції або сценарію.


7
Це не правильно - ОП спеціально просить вийти зі сценарію з функції . Returnпросто повернеться з функції, а не зі сценарію. ( Returnна найвищому рівні сценарій припиняє сценарій, але це не питання.)
— Майкл Соренс

1
ця відповідь насправді коментує відповідь EverydayNerd?
— тікасіх

22

Викинути виняток буде добре, особливо якщо ви хочете уточнити причину помилки:

throw "Error Message"

Це призведе до помилки закінчення.


3
Я не думаю, що це додає більше відповіді Грега Брея майже на рік раніше stackoverflow.com/a/20556550/695671
— Jason S

12

Можливо, краще використовувати «пастку». Пастка PowerShell задає блок-код, який потрібно запустити, коли відбувається закінчення або помилка. Тип

Get-Help about_trap

щоб дізнатися більше про заяву про пастку.


10

Я випадково виявив, що (наприклад , там , де мітка не існує ), як видається, вибивається з усього сценарію (навіть з-за функції) та зберігає хост живим. Таким чином, ви можете створити функцію, яка розбиває сценарій з будь-якого місця (наприклад, рекурсивний цикл), не знаючи поточного обсягу (і створюючи мітки):Break <UnknownLabel>Break ScriptScript

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

1
Ваш відповідь вірно, але знайте , що це може викликати проблеми для абонентів вашого скрипта , якщо вони НЕ згодні з вашим бажанням вийти весь сценарій: stackoverflow.com/questions/45746588 / ...
— DannyMeister

5

Я використовував це для повторної програми. Я не знаю, чи це допомогло б, але це просто, якщо заява вимагає лише двох різних записів. Для мене це працювало в силі.

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

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

Не знаю, чи це допомагає, але я вважаю, що це буде відповідно до припинення програми після запуску програми. Однак у цьому випадку для кожного визначеного входу потрібен перерахований та категоризований вихід. Ви також можете мати виклик виходу на новий рядок підказок та припиняти програму таким чином.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.