Ne zaman Yazma Hatası yazıp Atmam gerekir? Sonlandırma veya sonlandırılmayan hatalar


145

PoshCode üzerinde bir Get-WebFile betiğine baktığımda, http://poshcode.org/3226 , bu garip-me bana karşı fark ettim:

$URL_Format_Error = [string]"..."
Write-Error $URL_Format_Error
return

Aşağıdakilerin aksine bunun nedeni nedir?

$URL_Format_Error = [string]"..."
Throw $URL_Format_Error

Ya da daha iyisi:

$URL_Format_Error = New-Object System.FormatException "..."
Throw $URL_Format_Error

Anladığım kadarıyla, sonlandırma olmayan hatalar için Write-Error ve hataları sonlandırmak için Throw kullanmalısınız, bu yüzden bana Write-Error ve ardından Return kullanmamalısınız. Bir fark var mı?


4
Ne demek istiyorsun? Write_error komut dosyasının devam etmesine izin veriyorsa, Write-Error'dan sonra bir return ifadesi olması çok anlaşılabilir. Hata yazılmıştır ve öncelikle işlevi çağıran koda geri dönersiniz. Atma hataları sonlandırdığı için, otomatik olarak sonlandırılır, böylece atış bildirimindeki bir iade ifadesi işe yaramaz
Gisli

1
@Gisli: Bu nota önemlidir returngelmez değil de arayana dönmek processbir (gelişmiş) fonksiyonunun bloğu; bunun yerine, boru hattındaki bir sonraki giriş nesnesine ilerler . Aslında, bu, sonlandırılmayan hatalar oluşturmak için tipik bir senaryodur: başka giriş nesnelerini işlemeye devam etmek hala mümkündür.
mklement0

1
Örneğin, veya tarafından tetiklenen deyim sonlandırma hatalarıyla aynı olmayan Throwbir komut dosyası sonlandırma hatası oluşturduğunu unutmayın . Get-Item -NoSuchParameter1 / 0
mklement0

Yanıtlar:


189

Write-Errorkullanıcıyı kritik olmayan bir hata hakkında bilgilendirmek istiyorsanız kullanılmalıdır. Varsayılan olarak, konsolda kırmızı metinle bir hata mesajı yazdırmak yeterlidir. Bir boru hattının veya döngünün devam etmesini durdurmaz. Throwdiğer yandan sonlandırma hatası denen şeyi üretir. Atma kullanırsanız, boru hattı ve / veya akım döngüsü sona erdirilir. Aslında , sonlandırma hatasını işlemek için a trapveya bir try/catchyapı kullanmadığınız sürece tüm yürütme sonlandırılır.

Eğer ayarlarsanız nota bir şey yoktur $ErrorActionPreferenceiçin"Stop" ve kullanımı Write-Erroro olacak bir sonlandırma hatası üretir .

Bağlantı verdiğiniz komut dosyasında şunu buluruz:

if ($url.Contains("http")) {
       $request = [System.Net.HttpWebRequest]::Create($url)
}
else {
       $URL_Format_Error = [string]"Connection protocol not specified. Recommended action: Try again using protocol (for example 'http://" + $url + "') instead. Function aborting..."
       Write-Error $URL_Format_Error
    return
   }

Bu işlevin yazarı, bu işlevin yürütülmesini durdurmak ve ekranda bir hata iletisi görüntülemek istemiş gibi görünüyor, ancak tüm komut dosyasının yürütülmesini durduramadı. Senaryo yazarı kullanmış olabilir, throwancak try/catchişlevi çağırırken bir kullanmak zorunda kalabilirsiniz .

returnbir işlev, komut dosyası veya komut dosyası bloğu olabilecek geçerli kapsamdan çıkacaktır. Bu en iyi kodla gösterilmiştir:

# A foreach loop.
foreach ( $i in  (1..10) ) { Write-Host $i ; if ($i -eq 5) { return } }

# A for loop.
for ($i = 1; $i -le 10; $i++) { Write-Host $i ; if ($i -eq 5) { return } }

Her ikisi için çıktı:

1
2
3
4
5

Burada bir yakala returnbirlikte kullanıyor ForEach-Object. Beklendiği gibi işlemeyi kırmaz.

Daha fazla bilgi:


Tamam, böylece Throw her şeyi durduracak, Write-Error + return sadece mevcut işlevi durduracaktır.
Bill Barry

@BillBarry Cevabımı bir açıklama ile biraz güncelledim return.
Andy Arismendi

İşletim sistemine uygun hata kodunun döndürülmesini sağlamak için Yazma Hatası ve ardından çıkış (1)? Bu hiç uygun mu?
pabrams

19

Arasındaki temel fark Yaz-Hata cmdlet'inin ve atış PowerShell içinde anahtar kelime eski basitçe olmasıdır yazdırır bazı metni standart hata akımına (stderr) ikincisi aslında ederken, sonlandırır çalıştıran komutu ya da fonksiyon işlenmesini, ardından ele hataya ilişkin bilgileri konsola göndererek PowerShell tarafından.

Verdiğiniz örneklerde ikisinin farklı davranışlarını gözlemleyebilirsiniz:

$URL_Format_Error = [string]"..."
Write-Error $URL_Format_Error
return

Bu örnekte, hata iletisi konsola gönderildikten sonra komut dosyasının yürütülmesini açıkça durdurmak için returnanahtar sözcük eklenmiştir . İkinci örnekte ise, sonlandırma örtük olarak aşağıdakiler tarafından yapıldığından anahtar kelime gerekli değildir :returnthrow

$URL_Format_Error = New-Object System.FormatException "..."
Throw $URL_Format_Error

2
$ ErrorActionPreference = "Durdur" varsa, Yazma Hatası da işlemi sonlandırır.
Michael Freidgeim

4
İyi bilgi, ancak PowerShell hatası akışı iken benzer üzere metin tabanlı diğer kabuklarda Stderr akışında tüm PowerShell akışları gibi, içerdiği nesneleri , yani [System.Management.Automation.ErrorRecord]otomatik toplanan varsayılan olarak örneklerini $Errorkoleksiyonunda ( $Error[0]En son hata içeriyor). Sadece Write-Errorbir dize ile kullansanız bile , o dize bir [System.Management.Automation.ErrorRecord]örneğe sarılır .
mklement0

17

Önemli : Mevcut yardım konularının maalesef karıştırdığı 2 tür sonlandırma hatası vardır :

  • kurtarılamayan belirli durumlarda cmdlet'ler ve bir .NET istisnası / PS çalışma zamanı hatasının oluştuğu ifadeler tarafından bildirildiği gibi, ifade sonlandırma hataları; yalnızca ifade sonlandırılır ve komut dosyası yürütme varsayılan olarak devam eder .

  • komut -terminating : (daha doğru hataları runspace-sonlandırıcı olarak ya tarafından tetiklenen)Throwveya hata-aksiyon tercih değişken / parametre değeri ile başka hata türlerinden birini artan ileStop.
    Yakalanmadığı sürece, mevcut çalışma alanını (iplik) sonlandırırlar; yani, yalnızca geçerli komut dosyasını değil, varsa tüm arayanlarını da sonlandırırlar).

PowerShell'in hata işlemesine kapsamlı bir genel bakış için bu GitHub dokümantasyon sorununa bakın .

Bu yazının geri kalanı, sonlandırma ile ifade sonlandırma hatalarına odaklanır .


Mevcut yararlı cevapları sorunun özüne odaklanarak tamamlamak için: Sonlandırıcı veya sonlandırıcı olmayan bir hatayı bildirmeyi nasıl seçersiniz ?

Cmdlet Hata Bildirimi yardımcı yönergeler içerir; Bana bir girişimi izin pragmatik özeti :

Sonlandırmayan hataların arkasındaki genel fikir , büyük giriş kümelerinin "hataya dayanıklı" işlenmesine izin vermektir : giriş nesnelerinin bir alt kümesinin işlenememesi (varsayılan olarak) - bir bütün olarak - potansiyel olarak uzun süren - işlemi iptal etmemelidir , otomatik değişkente toplanan hata kayıtları aracılığıyla bildirildiği gibi hataları incelemenize ve yalnızca başarısız olan nesneleri daha sonra yeniden işlemenize olanak tanır $Error.

  • Cmdlet'iniz / gelişmiş işleviniz varsa SÜRE OLMAYAN bir hata bildirin:

    • boru hattı girişi ve / veya dizi değerli parametreler aracılığıyla MULTIPLE giriş nesnelerini kabul eder , AND
    • SPECIFIC giriş nesneleri için hatalar oluşur VE
    • bu hatalar İLK'DE DAHA FAZLA giriş nesnesinin İŞLENMESİNİ ÖNLEMEZ ( durumsal olarak , hiç giriş nesnesi kalmamış olabilir ve / veya önceki giriş nesneleri zaten başarıyla işlenmiş olabilir).
      • Gelişmiş fonksiyonlar, kullanım $PSCmdlet.WriteError()dışı bir sonlandırma hatayı bildirmek için ( Write-Errormaalesef neden olmaz $?üzere ayarlanmış olması $Falsehalinde arayanın kapsamı - bakınız bu GitHub sorunu ).
      • Taşıma olmayan bir sonlandırma hatası: $?En son komutu bildirdi olmadığını söyler en az bir sigara sonlandırma hatası.
        • Bu nedenle $?varlık $False, giriş nesnelerinin herhangi bir (boş olmayan) alt kümesinin , muhtemelen tüm kümenin düzgün bir şekilde işlenmediği anlamına gelebilir .
        • Tercih değişkeni $ErrorActionPreferenceve / veya ortak cmdlet parametresi -ErrorAction, sonlandırılmayan hataların davranışını (yalnızca) hata çıktı davranışı ve sonlandırma yapmayan hataların komut dosyası sonlandırılan hatalara yükseltilip iletilmeyeceği açısından değiştirebilir.
  • Bir bildirme TABLOSU-sonlandırma hatayı Diğer tüm durumlarda .

    • Özellikle, yalnızca bir SINGLE veya NO giriş nesnesini kabul eden ve NO veya SINGLE çıkış nesnesini çıkaran veya yalnızca parametre girdisini alan bir cmdlet / gelişmiş işlevde bir hata oluşursa ve verilen parametre değerleri anlamlı çalışmayı önler.
      • Gelişmiş işlevlerde, $PSCmdlet.ThrowTerminatingError()ifade sonlandırma hatası oluşturmak için kullanmanız gerekir .
      • Buna karşılık, Throwanahtar kelimenin tüm komut dosyasını (teknik olarak geçerli iş parçacığı ) durduran bir komut dosyası sonlandırma hatası oluşturduğunu unutmayın .
      • Taşıma açıklamada sonlandıran hata: Bir try/catchişleyici veya trapdeyim (ki kullanılabilir olamaz ile kullanılabilir olmayan sonlandırma hataları), ancak not bile deyim varsayılan olarak -terminating hatalar çalışmasını senaryonun kalanını engellemez. Olduğu gibi sigara sonlandırma hataları, $?yansıtan $Falsebir önceki ifadesi bir deyim-sonlandırma hatayı tetikleyen eğer.

Ne yazık ki, PowerShell'in kendi çekirdek cmdlet'lerinin tümü şu kurallara uymaz :

  • Başarısız olma olasılığı düşük olsa da, New-TemporaryFile(PSv5 +), boru hattı girdisini kabul etmemeye ve yalnızca bir çıktı nesnesi üretmemesine rağmen başarısız olursa sonlandırma hatası bildirir - bu en azından PowerShell [Core] 7.0'dan beri düzeltilmiştir, ancak bkz: GitHub sorun .

  • Resume-Jobadlı kişinin yardımı, desteklenmeyen bir iş türünün ( yalnızca iş akışı işleri için geçerli Start-Jobolduğu için desteklenmeyen bir iş gibi) geçirilmesinin sonlandırma hatasına neden olduğunu iddia ediyor, ancak bu PSv5.1'den itibaren doğru değil.Resume-Job


8

Write-Errorfonksiyonun tüketicisinin hata mesajını bastırmasını sağlar -ErrorAction SilentlyContinue(alternatif olarak -ea 0). Süre throwgerektirir birtry{...} catch {..}

Denemek için ... ile yakalayın Write-Error:

try {
    SomeFunction -ErrorAction Stop
}
catch {
    DoSomething
}

Hata mesajını bastırmak istiyorsanız neden Yazma Hatasını aramanız gerekiyor?
Michael Freidgeim

8

Andy Arismendi'nin cevabına ek olarak :

İster Yaz-Hata işlemini sonlandırır olmadığına bağlıdır $ErrorActionPreferenceayarında.

Önemsiz olmayan komut dosyaları için $ErrorActionPreference = "Stop"bir olduğunu tavsiye edilen ayar hızlı başarısız.

"PowerShell'in hatalarla ilgili varsayılan davranışı, hataya devam edecek ... çok VB6" On Error Resume Next "-ish"

( http://codebetter.com/jameskovacs/2010/02/25/the-exec-problem/ adresinden )

Ancak, Write-Errorçağrıları sonlandırır.

Kullanmak için Yaz-Hatası olursa olsun diğer ortam ayarlarının olmayan bir sonlandırma komutu olarak kullanabileceğiniz ortak bir parametre -ErrorAction değeri ile Continue:

 Write-Error "Error Message" -ErrorAction:Continue

0

Kodu okumanız doğru ise, o zaman haklısınız demektir. Sonlandırma hataları kullanılmalıdır throwve .NET türleriyle uğraşıyorsanız, .NET istisna kurallarına uymanız da yararlı olacaktır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.