2015-08-08 14 views
42

ja po prostu nie lubię składnię:Lepszym sposobem sprawdzenia, czy ścieżka istnieje, czy nie w PowerShell

if (Test-Path $path) { ... } 

i

if (-not (Test-Path $path)) { ... } 
if (!(Test-Path $path)) { ... } 

zwłaszcza istnieje zbyt wiele nawias i nie bardzo czytelny przy sprawdzaniu "nie istnieje" dla tak powszechnego użytku. Jaki jest lepszy sposób na zrobienie tego?

Aktualizacja: Mój obecny rozwiązaniem jest użycie aliasów dla exist i not-exist jak wyjaśniono here.

Powiązane problem w repozytorium PowerShell: https://github.com/PowerShell/PowerShell/issues/1970

+1

Można użyć 'try {Test-Path -EA Zatrzymaj $ path; #stuff do zrobienia, jeśli znaleziono} catch {# rzeczy do zrobienia, jeśli nie znaleziono} ' – Eris

+1

Pokrewny problem: https://github.com/PowerShell/PowerShell/issues/1970 – orad

+1

Ty, mój przyjacielu, używasz niewłaściwego narzędzia, jeśli chcą czytelności. – GenuineRex

Odpowiedz

62

Jeśli potrzebujesz tylko alternatywy dla składni cmdlet, szczególnie dla plików, użyj File.Exists().Metoda netto:

if(![System.IO.File]::Exists($path)){ 
    # file with path $path doesn't exist 
} 

Jeśli, z drugiej strony, chcesz ogólnego przeznaczenia zanegowane alias Test-Path, tu jest jak należy to zrobić:

# Gather command meta data from the original Cmdlet (in this case, Test-Path) 
$TestPathCmd = Get-Command Test-Path 
$TestPathCmdMetaData = New-Object System.Management.Automation.CommandMetadata $TestPathCmd 

# Use the static ProxyCommand.GetParamBlock method to copy 
# Test-Path's param block and CmdletBinding attribute 
$Binding = [System.Management.Automation.ProxyCommand]::GetCmdletBindingAttribute($TestPathCmdMetaData) 
$Params = [System.Management.Automation.ProxyCommand]::GetParamBlock($TestPathCmdMetaData) 

# Create wrapper for the command that proxies the parameters to Test-Path 
# using @PSBoundParameters, and negates any output with -not 
$WrappedCommand = { 
    try { -not (Test-Path @PSBoundParameters) } catch { throw $_ } 
} 

# define your new function using the details above 
$Function:notexists = '{0}param({1}) {2}' -f $Binding,$Params,$WrappedCommand 

notexists będzie teraz zachowywać dokładnie jak Test-Path, ale zawsze zwracamy przeciwny wynik:

PS C:\> Test-Path -Path "C:\Windows" 
True 
PS C:\> notexists -Path "C:\Windows" 
False 
PS C:\> notexists "C:\Windows" # positional parameter binding exactly like Test-Path 
False 

Jak już pokazano siebie, przeciwnie jest bardzo proste, wystarczy alias exists do Test-Path:

PS C:\> New-Alias exists Test-Path 
PS C:\> exists -Path "C:\Windows" 
True 
+1

Jeśli '$ ścieżka' jest" specjalny ", tak jak w przypadku Dostawcy Powershell (myśl HKLM: \ SOFTWARE \ ...), to nie będzie to możliwe. – Eris

+3

@Eris pytanie prosi o sprawdzenie, czy * plik * istnieje, czy nie –

+0

Głosowałem za twoją odpowiedzią, ale naprawdę chciałem mieć rozwiązanie ogólnego celu. – orad

5

Dodaj następujące aliasy. Myślę, że powinny one być udostępniane w PowerShell domyślnie:

function not-exist { -not (Test-Path $args) } 
Set-Alias !exist not-exist -Option "Constant, AllScope" 
Set-Alias exist Test-Path -Option "Constant, AllScope" 

z tym, że sprawozdanie warunkowe zmieni się na:

if (exist $path) { ... } 

i

if (not-exist $path)) { ... } 
if (!exist $path)) { ... } 
+3

Jeśli chcesz, aby zespół PowerShell dodał alias "istniejący", prześlij żądanie funkcji za pomocą Microsoft Connect –

+3

OK, tutaj jest [zgłoszenie do tego w witrynie Microsoft Connect] (https://connect.microsoft.com/PowerShell/ feedbackdetail/view/1643846 /). Proszę zagłosować! – orad

+1

Mimo że sam odpowiedziałem, akceptuję @ mathias-r-jessen's [odpowiedź] (http://stackoverflow.com/a/31896279/450913), ponieważ lepiej obsługuje parametry. – orad

12

Rozwiązanie alias zostanie zaksięgowana jest sprytnie, ale argumentowałbym przeciwko jego użyciu w skryptach, z tego samego powodu, dla którego nie lubię używać żadnych aliasów w skryptach; ma to niekorzystny wpływ na czytelność.

Jeśli jest to coś, co chcesz dodać do swojego profilu, aby można było pisać szybkie polecenia lub używać go jako powłoki, wtedy mogłem zobaczyć, że ma to sens.

Można rozważyć rur zamiast:

if ($path | Test-Path) { ... } 
if (-not ($path | Test-Path)) { ... } 
if (!($path | Test-Path)) { ... } 

Alternatywnie, dla ujemnej podejścia, jeśli odpowiednie dla Twojego kodu, można zrobić to pozytywna kontrola następnie użyć else dla przecząca:

if (Test-Path $path) { 
    throw "File already exists." 
} else { 
    # The thing you really wanted to do. 
} 
+1

Podobają mi się tutaj rurociągi, ale proponowane kontrole negatywów są niepoprawne bez nawiasów, lub zawsze będą oznaczać "Fałsz". Musisz zrobić to jak 'if (-nie ($ path | Test-Path)) {...}'. – orad

+1

@Jeśli masz rację! Właściwie to w tym przypadku jest negatywem. Uśpiłem się w fałszywym poczuciu bezpieczeństwa, nie rzucając wyjątku, kiedy to się nie udało. Wywołanie go w oryginalny sposób rzuca wyjątek, dzięki czemu łatwiej jest złapać problem. – briantist

Powiązane problemy