2015-08-08 3 views
42

Ich mag einfach nicht die Syntax:Eine bessere Möglichkeit, zu überprüfen, ob ein Pfad existiert oder nicht in Powershell

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

und

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

vor allem zu vielen Klammern und nicht sehr lesbar bei der Überprüfung auf "nicht vorhanden" für eine solche allgemeine Verwendung. Was ist ein besserer Weg, dies zu tun?

Update: Meine aktuelle Lösung ist Aliase für exist und not-exist zu verwenden, wie here erläutert.

Verwandte Problem in Powershell-Repository: https://github.com/PowerShell/PowerShell/issues/1970

+1

Sie verwenden könnten 'try {Test-Path -EA Stopp $ Pfad; #stuff zu tun, wenn gefunden} catch {# Sachen zu tun, wenn nicht gefunden} ' – Eris

+1

Related Problem: https://github.com/PowerShell/PowerShell/issues/1970 – orad

+1

Sie, mein Freund, verwenden das falsche Werkzeug, wenn Sie will Lesbarkeit. – GenuineRex

Antwort

62

Wenn Sie nur eine Alternative zur Cmdlet-Syntax speziell für Dateien wünschen, verwenden Sie die File.Exists().NET-Methode:

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

Wenn auf der anderen Seite wollen Sie ein Allzweck-Alias ​​für Test-Path negiert wird, ist hier, wie Sie es tun sollten:

# 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 wird nun verhalten genau wie Test-Path, aber immer das umgekehrte Ergebnis zurück:

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 

Wie Sie bereits selbst gezeigt hat, ist das Gegenteil ganz einfach, nur alias exists zu Test-Path:

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

Wenn '$ path'" special "ist, wie bei einem Powershell Provider (denke HKLM: \ SOFTWARE \ ...) dann wird dies kläglich scheitern. – Eris

+3

@Eris Frage speziell fragt zu überprüfen, ob eine * Datei * existiert oder nicht –

+0

Ich wählte Ihre Antwort, aber ich wollte wirklich eine allgemeine Lösung haben. – orad

5

folgende Aliasnamen hinzufügen. Ich denke, diese in Powershell standardmäßig zur Verfügung gestellt werden sollten:

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

Damit die bedingten Anweisungen wird sich ändern:

if (exist $path) { ... } 

und

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

Wenn Sie möchten, dass das PowerShell-Team einen "bestehenden" Alias ​​hinzufügt, sollten Sie eine Feature-Anfrage über Microsoft Connect senden. –

+3

OK, hier ist die [Einreichung dafür bei Microsoft Connect] (https://connect.microsoft.com/PowerShell/ Feedbackdetail/view/1643846 /). Bitte stimmt ab! – orad

+1

Obwohl ich selbst antwortete, akzeptiere ich @ mathias-r-jessens [antwort] (http://stackoverflow.com/a/31896279/450913), weil es Parameter besser handhabt. – orad

12

Die Alias-Lösung, die Sie geschrieben ist clever, aber ich würde gegen seine Verwendung in Skripten argumentieren, aus dem gleichen Grund mag ich keine Aliase in Skripten verwenden; es schadet der Lesbarkeit.

Wenn dies etwas ist, das Sie zu Ihrem Profil hinzufügen möchten, damit Sie schnell Befehle eingeben oder es als Shell verwenden können, dann könnte ich sehen, dass das Sinn macht.

Sie könnten Rohrleitungen sollten Sie stattdessen:

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

Alternativ für den negativen Ansatz, gegebenenfalls für Ihren Code, können Sie es eine positive Kontrolle dann else machen verwenden für die negative:

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

Ich mag die Rohrleitungen hier, aber Ihre vorgeschlagene Überprüfung auf Negative ist falsch ohne Klammern, oder es wird immer zu "False" ausgewertet. Sie müssen es tun wie 'if (-not ($ path | Test-Path)) {...}'. – orad

+1

@orad du bist richtig! Eigentlich ist das in diesem Fall ein Negativ der Rohrleitung. Ich wurde in ein falsches Gefühl der Sicherheit eingelullt, indem es keine Ausnahme auswarf, als es tatsächlich fehlschlug. Wenn Sie den ursprünglichen Weg aufrufen, wird eine Ausnahme ausgelöst, die das Auffinden des Problems erleichtert. – briantist

Verwandte Themen