Chấm dứt tập lệnh trong PowerShell


394

Tôi đã tìm cách chấm dứt tập lệnh PowerShell (PS1) khi xảy ra lỗi không thể phục hồi trong một hàm. Ví dụ:

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

Tất nhiên không có những thứ như $host.Exit(). Có $host.SetShouldExit(), nhưng điều này thực sự đóng cửa sổ giao diện điều khiển, đó không phải là điều tôi muốn. Những gì tôi cần là một cái gì đó tương đương với Python sys.exit()sẽ đơn giản dừng thực thi tập lệnh hiện tại mà không cần quảng cáo thêm.

Chỉnh sửa: Vâng, nó chỉ exit. Tât nhiên.


8
Nếu bạn muốn tránh đóng cửa sổ PowerShell hoặc ISE trong trường hợp của tôi; sử dụng "trở lại" thay thế. Nó chỉ kết thúc bối cảnh chạy hiện tại. "Người mới" giải thích cặn kẽ tất cả các lựa chọn cho mục đích giáo dục; bạn có thể muốn xem xét thay đổi câu trả lời được chấp nhận của mình (hiện tại vẫn có nhiều phiếu bầu hơn) cho người dùng StackOverflow trong tương lai. Nó sẽ cho phép bạn gỡ lỗi kịch bản là tốt.
ZaxLofful

Điều này có trả lời câu hỏi của bạn không? Chính xác thì "thoát" trong PowerShell là gì?
Mark Schultheiss

Câu trả lời:


389

Bạn nên sử dụng các exittừ khóa .


15
Chúa ơi, nếu tôi không bị cuốn vào việc cố gắng tìm ra cách làm những điều này một cách khéo léo thì có lẽ tôi đã thử làm điều đó để bắt đầu và tìm ra nó hoạt động :) Cảm ơn.
kprobst

118
Làm thế nào đây là câu trả lời được chấp nhận? Nó đặc biệt "đóng cửa sổ giao diện điều khiển" mà người hỏi nói "đó không phải là điều tôi muốn."
claudekennilol

3
@claudekennilol Chỉ người hỏi mới có thể chấp nhận câu trả lời. Hoặc là họ đã bỏ lỡ thực tế là lối ra được cho là đóng cửa sổ, hoặc họ đã thay đổi ý định và cho rằng có thể chấp nhận được cho mục đích của họ.
Iszi

3
Nó không đóng cửa sổ giao diện điều khiển trong v3 hoặc v4 mà tôi sử dụng. Vâng, nó sẽ nếu bạn chạy tập lệnh từ explorer, nhưng cho dù bạn kết thúc tập lệnh như thế nào thì nó cũng sẽ làm được điều đó. Nếu chạy từ cửa sổ lệnh PowerShell, nó không đóng cửa sổ.
Joshua Nurchot

14
Câu trả lời của New Guy kỹ lưỡng hơn rất nhiều và những người giải thích được đánh dấu là đã chấp nhận.
Jim Aho

585

Tôi nhận ra đây là một bài viết cũ nhưng tôi thấy mình quay lại chủ đề này rất nhiều vì đây là một trong những kết quả tìm kiếm hàng đầu khi tìm kiếm chủ đề này. Tuy nhiên, sau đó tôi luôn bối rối hơn khi đến vì những thông tin mâu thuẫn. Cuối cùng, tôi luôn phải thực hiện các bài kiểm tra của riêng mình để tìm ra nó. Vì vậy, lần này tôi sẽ đăng những phát hiện của tôi.

TL; DR Hầu hết mọi người sẽ muốn sử dụng Exitđể chấm dứt một tập lệnh đang chạy. Tuy nhiên, nếu tập lệnh của bạn chỉ đơn thuần là khai báo các hàm để sau này được sử dụng trong trình bao, thì bạn sẽ muốn sử dụngReturn trong các định nghĩa của các hàm đã nói.

Thoát vs Quay lại vs Phá

  • Lối ra: Điều này sẽ "thoát" bối cảnh hiện đang chạy. Nếu bạn gọi lệnh này từ một tập lệnh, nó sẽ thoát khỏi tập lệnh. Nếu bạn gọi lệnh này từ shell, nó sẽ thoát khỏi shell.

    Nếu một hàm gọi lệnh Thoát, nó sẽ thoát khỏi bối cảnh mà nó đang chạy. Vì vậy, nếu chức năng đó chỉ được gọi từ trong một tập lệnh đang chạy, nó sẽ thoát khỏi tập lệnh đó. Tuy nhiên, nếu tập lệnh của bạn chỉ khai báo hàm để nó có thể được sử dụng từ trình bao hiện tại và bạn chạy hàm đó từ trình bao, nó sẽ thoát khỏi trình bao vì trình bao là ngữ cảnh trong đó hàm chứa Exitlệnh đang chạy.

    Lưu ý: Theo mặc định nếu bạn nhấp chuột phải vào tập lệnh để chạy tập lệnh trong PowerShell, khi tập lệnh được chạy xong, PowerShell sẽ tự động đóng. Điều này không có gì để làm với Exitlệnh hoặc bất cứ điều gì khác trong kịch bản của bạn. Đây chỉ là một hành vi PowerShell mặc định cho các tập lệnh đang được chạy bằng phương thức chạy tập lệnh cụ thể này. Điều này cũng đúng với các tệp bó và cửa sổ Dòng lệnh.

  • Trả về: Điều này sẽ trở về điểm gọi trước đó. Nếu bạn gọi lệnh này từ một tập lệnh (bên ngoài bất kỳ chức năng nào), nó sẽ trở về trình bao. Nếu bạn gọi lệnh này từ shell, nó sẽ trở về shell (là điểm gọi trước đó cho một lệnh được chạy từ shell). Nếu bạn gọi lệnh này từ một hàm, nó sẽ trở về nơi mà hàm được gọi từ đó.

    Việc thực hiện bất kỳ lệnh nào sau điểm gọi mà nó được trả về sẽ tiếp tục từ điểm đó. Nếu một tập lệnh được gọi từ shell và nó chứa Returnlệnh bên ngoài bất kỳ hàm nào thì khi nó quay trở lại shell, sẽ không còn lệnh nào để chạy, do đó, Returnsử dụng theo cách này về cơ bản giống như Exit.

  • Break: Điều này sẽ thoát ra khỏi các vòng lặp và trường hợp chuyển đổi. Nếu bạn gọi lệnh này trong khi không ở trong một vòng lặp hoặc trường hợp chuyển đổi, nó sẽ thoát ra khỏi tập lệnh. Nếu bạn gọi Breakbên trong một vòng lặp được lồng trong một vòng lặp, nó sẽ chỉ thoát ra khỏi vòng lặp mà nó được gọi.

    Ngoài ra còn có một tính năng thú vị về Breaknơi bạn có thể tiền tố một vòng lặp với nhãn và sau đó bạn có thể thoát ra khỏi vòng lặp được gắn nhãn đó ngay cả khi Breaklệnh được gọi trong một số nhóm lồng trong vòng lặp được gắn nhãn đó.

    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
Cũng đáng lưu ý rằng Exitcó thể lấy mã trả về làm tham số (mặc định là 0) - vd Exit 3.
aucuparia

2
Tôi đồng ý, đây là một câu trả lời tốt hơn nhiều. "Phá vỡ" có thể có hậu quả không lường trước.
iagomartinez

Tôi không chắc nhận xét của bạn về "Thoát" là hoàn toàn chính xác mặc dù đây là một câu trả lời tuyệt vời về tổng thể. Lối ra dường như đang khiến ISE đóng cửa theo cách mà dường như không có gì khác đang làm. Đơn giản là thoát khỏi bối cảnh (ví dụ, hoàn thành kịch bản) không làm điều này.
Bill K

1
@BillK Thật vậy. Tôi đã cập nhật câu trả lời. Khi tôi lần đầu tiên viết bài này, tôi nhớ không tìm thấy bất kỳ tài liệu chính thức nào về Thoát. Sau đó tôi đã làm một Get-Command ExitGet-Alias Exitkhông có kết quả. Sau đó tôi nhìn xem nó có phải là một từ khóa không và không tìm thấy tài liệu chính thức nào về nó. Tuy nhiên, nhìn vào nó bây giờ, tôi không biết làm thế nào tôi đi đến kết luận đó. Rõ ràng đó là một từ khóa ( technet.microsoft.com/en-us/l Library / hh847744.aspx ). Có lẽ bởi vì Thoát là một trong những từ khóa duy nhất không có chủ đề trợ giúp về chính nó và do đó, danh sách các chủ đề trong thanh bên trái không bao gồm nó.
Guy mới

6
Còn ném thì sao?
JDC

80

Exitcũng sẽ thoát PowerShell. Nếu bạn muốn "thoát" khỏi chức năng hoặc tập lệnh hiện tại - hãy sử dụng 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
Vui lòng không sử dụng breakkhi muốn thoát ra khỏi chức năng hiện tại ... việc gọi các tập lệnh cũng có thể bị gián đoạn!
DanielMeister

49

Lỗi ghilỗi không chấm dứt và lỗi ném là để chấm dứt lỗi

Lệnh ghép ngắn ghi lỗi tuyên bố lỗi không kết thúc. Theo mặc định, lỗi được gửi trong luồng lỗi đến chương trình máy chủ sẽ được hiển thị, cùng với đầu ra.

Các lỗi không kết thúc ghi một lỗi vào luồng lỗi, nhưng chúng không dừng xử lý lệnh. Nếu một lỗi không kết thúc được khai báo trên một mục trong bộ sưu tập các mục đầu vào, lệnh tiếp tục xử lý các mục khác trong bộ sưu tập.

Để khai báo lỗi kết thúc, hãy sử dụng từ khóa Ném. Để biết thêm thông tin, hãy xem about_Throw ( http://go.microsoft.com/fwlink/?LinkID=145153 ).


4
Đây có vẻ là cách chính xác nhất để chấm dứt một hoạt động có lỗi. Nó ủy quyền cho người gọi để cố gắng xử lý lỗi, điều này tốt hơn nhiều so với việc cố gắng chấm dứt đột ngột.
Paul Turner

Đối với tôi, ít nhất là trong các chức năng mô-đun, ném ra nhưng không đặt mã thoát. Điều này đã được thực hiện thông qua CLI, vd powershell -command "& module-function ...". Tôi cần phải chuyển đổi các hàm đó để chuyển sang một gói thử bắt và thoát khỏi gói bắt đó để thực sự xuất mã thoát lỗi.
Josh

2
Đừng quên $PSCmdlet.ThrowTerminatingError()những trường hợp đó khi ném chỉ không thể hoàn thành công việc (vấn đề đã biết không có lỗi kết thúc từ throw)
Djarid

33

Chấm dứt quá trình này và cung cấp cho hệ điều hành cơ bản mã thoát được chỉ định.

https://msdn.microsoft.com/en-us/l Library / system.en môi.exit% 28v = vs.110% 29.aspx

[Environment]::Exit(1)

Điều này sẽ cho phép bạn thoát với một mã thoát cụ thể, có thể được chọn từ người gọi.


3
Trong PowerShell, bạn chỉ cần sử dụng Lối thoát tích hợp cho việc này, vd Exit 1.
Jonas

3
Lối thoát tích hợp sẽ không luôn hoạt động như bạn mong đợi. Hãy thử điều này trong powershell: "Thoát 5"> test1.ps1 powershell.exe. \ Test1.ps1 $ lastexitcode "[Môi trường] :: Thoát (5)"> test2.ps1 powershell.exe. \ Test2.ps1 $ lastexitcode
gabriwinter

1
[Environment]::Exit(1)có tác dụng phụ khi thoát khỏi cửa sổ powershell của tôi khi tôi gọi nó trong một tập lệnh, khi mà việc sử dụng exitkhông xuất hiện để làm như vậy.
Josh Desmond

25

Tôi nghĩ rằng bạn đang tìm kiếm Returnthay vì Break. Break thường được sử dụng cho các vòng lặp và chỉ ngắt từ khối mã trong cùng. Sử dụng Quay lại để thoát một chức năng hoặc tập lệnh.


7
Điều này không đúng - OP đặc biệt yêu cầu thoát khỏi tập lệnh từ bên trong hàm . Returnsẽ chỉ đơn giản là trả về từ hàm, không phải từ tập lệnh. ( ReturnTại đầu mức độ của một kịch bản sẽ chấm dứt kịch bản, nhưng đó không phải là câu hỏi.)
Michael Sorens

1
đây có phải là 'câu trả lời' thực sự nhận xét về câu trả lời của EverydayNerd không?
tkokasih

22

Ném một ngoại lệ sẽ tốt đặc biệt nếu bạn muốn làm rõ lý do lỗi:

throw "Error Message"

Điều này sẽ tạo ra một lỗi kết thúc.


3
Tôi không nghĩ điều này bổ sung nhiều hơn câu trả lời của Greg Bray gần một năm trước stackoverflow.com/a/20556550/695671
Jason S

12

Có thể tốt hơn là sử dụng "bẫy". Bẫy PowerShell chỉ định một khóa mã để chạy khi xảy ra lỗi hoặc chấm dứt. Kiểu

Get-Help about_trap

để tìm hiểu thêm về tuyên bố bẫy.


10

Tôi tình cờ phát hiện ra rằng (ví dụ , đơn giản là nơi nhãn không tồn tại ) dường như thoát ra khỏi toàn bộ tập lệnh (ngay cả từ bên trong một chức năng) và giữ cho máy chủ tồn tại. Bằng cách này, bạn có thể tạo một hàm phá vỡ tập lệnh từ bất kỳ đâu (ví dụ: vòng lặp đệ quy) mà không cần biết phạm vi hiện tại (và tạo nhãn):Break <UnknownLabel>Break ScriptScript

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

1
Câu trả lời của bạn là đúng, nhưng lưu ý rằng điều này có thể gây ra sự cố cho người gọi tập lệnh của bạn nếu họ không đồng ý với mong muốn thoát khỏi toàn bộ tập lệnh: stackoverflow.com/questions/45746588/
DannyMeister

5

Tôi đã sử dụng điều này để chạy lại chương trình. Tôi không biết liệu nó có giúp ích gì không, nhưng thật đơn giản nếu câu lệnh chỉ yêu cầu hai mục nhập khác nhau. Nó làm việc trong powershell cho tôi.

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

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

Không biết điều này có giúp ích gì không, nhưng tôi tin rằng điều này sẽ cùng với việc chấm dứt một chương trình sau khi bạn đã chạy nó. Tuy nhiên, trong trường hợp này, mọi đầu vào được xác định đều yêu cầu đầu ra được liệt kê và phân loại. Bạn cũng có thể yêu cầu thoát ra một dòng nhắc mới và chấm dứt chương trình theo cách đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.