PowerShell'de bir yolun olup olmadığını kontrol etmenin daha iyi bir yolu


124

Sadece şu sözdizimini sevmiyorum:

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

ve

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

özellikle çok fazla parantez var ve bu kadar yaygın bir kullanım için "yok" olup olmadığı kontrol edildiğinde çok okunabilir değil. Bunu yapmanın daha iyi bir yolu nedir?

Güncelleme: Benim şu anki çözüm için diğer adlar kullanmaktır existve not-existolarak açıklanabilir burada .

PowerShell deposundaki ilgili sorun: https://github.com/PowerShell/PowerShell/issues/1970


2
Kullanabilirsiniztry{ Test-Path -EA Stop $path; #stuff to do if found } catch { # stuff to do if not found }
Eris

Yanıtlar:


131

Yalnızca cmdlet sözdizimine bir alternatif istiyorsanız, özellikle dosyalar için, File.Exists().NET yöntemini kullanın :

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

Öte yandan, genel amaçlı reddedilmiş bir takma ad Test-Pathistiyorsanız, bunu şu şekilde yapmanız gerekir:

# 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şimdi tam olarak aynı şekilde davranacak Test-Path, ancak her zaman zıt sonucu döndürecektir:

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

Zaten kendini gösterdiğin gibi, karşısında oldukça kolaydır sadece takma existsiçin Test-Path:

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

1
Eğer $pathbir PowerShell Sağlayıcısı olduğu gibi "özel" dir (HKLM düşünüyorum: \ SOFTWARE \ ...) o zaman bu sefil başarısız olur.
Eris

4
@Eris sorusu özellikle bir dosyanın var olup olmadığını kontrol etmenizi ister
Mathias

1
Kesinlikle ve anında yeni bir cmdlet oluşturmak harika. Neredeyse bir takma ad kadar ele alınamaz, ama yine de gerçekten düzgün :)
Eris

Güzel! PS'nin bunun için yerel destek eklemesi gerektiğini düşünüyorum.
orad

4
@orad Onlara bunu yaptıracağından ciddi şüpheliyim. "Çok fazla parantez" çok öznel bir mantıktır ve dil tasarımından / şartnamesinden sapmayı gerçekten hak etmiyor. FWIW, eğer parantezlerden bu kadar nefret ediyorsanız @ briantist tarafından daha iyi bir alternatif olarak önerilen if / else yapısına da katılıyorum:if(Test-Path $path){}else{ # do your thing }
Mathias R. Jessen

38

Gönderdiğiniz diğer ad çözümü akıllıca, ancak komut dosyalarında kullanılmasına karşı çıkıyorum, aynı nedenle komut dosyalarında herhangi bir takma ad kullanmayı sevmiyorum; okunabilirliğe zarar verme eğilimindedir.

Bu, profilinize eklemek istediğiniz bir şeyse, hızlı komutlar yazabilir veya bunu bir kabuk olarak kullanabilirsiniz, o zaman bunun mantıklı olduğunu görebilirim.

Bunun yerine boruyu düşünebilirsiniz:

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

Alternatif olarak, olumsuz yaklaşım için, kodunuz için uygunsa, bunu pozitif bir kontrol yapabilir ve ardından elsenegatif için kullanabilirsiniz :

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

1
Buradaki boruları beğendim, ancak negatifler için önerdiğiniz kontroller parantez olmadan yanlış veya her zaman olarak değerlendirilecektir False. Beğenmen gerek if (-not ($path | Test-Path)) { ... }.
orad

1
@orad haklısın! Aslında bu, bu durumda borunun olumsuzdur. Başarısız olduğu gerçeğine rağmen bir istisna yapmayarak sahte bir güvenlik duygusuna kapıldım. Buna orijinal yol demek, bir istisna atar ve sorunu yakalamayı kolaylaştırır.
briantist

10

Aşağıdaki takma adları ekleyin. Bunların varsayılan olarak PowerShell'de sunulması gerektiğini düşünüyorum:

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

Bununla birlikte, koşullu ifadeler şu şekilde değişecektir:

if (exist $path) { ... }

ve

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

4
PowerShell ekibinin "mevcut" bir diğer ad eklemesini istiyorsanız, Microsoft Connect
Mathias R. Jessen

1
Kendim cevaplamış olsam da @ mathias-r-jessen'in cevabını kabul ediyorum çünkü parametreleri daha iyi işliyor .
orad

2

Başka bir seçenek IO.FileInfode, size çok fazla dosya bilgisi veren ve sadece bu türü kullanarak hayatı kolaylaştıran kullanımıdır:

PS > mkdir C:\Temp
PS > dir C:\Temp\
PS > [IO.FileInfo] $foo = 'C:\Temp\foo.txt'
PS > $foo.Exists
False
PS > New-TemporaryFile | Move-Item -Destination C:\Temp\foo.txt
PS > $foo.Refresh()
PS > $foo.Exists
True
PS > $foo | Select-Object *


Mode              : -a----
VersionInfo       : File:             C:\Temp\foo.txt
                    InternalName:
                    OriginalFilename:
                    FileVersion:
                    FileDescription:
                    Product:
                    ProductVersion:
                    Debug:            False
                    Patched:          False
                    PreRelease:       False
                    PrivateBuild:     False
                    SpecialBuild:     False
                    Language:

BaseName          : foo
Target            : {}
LinkType          :
Length            : 0
DirectoryName     : C:\Temp
Directory         : C:\Temp
IsReadOnly        : False
FullName          : C:\Temp\foo.txt
Extension         : .txt
Name              : foo.txt
Exists            : True
CreationTime      : 2/27/2019 8:57:33 AM
CreationTimeUtc   : 2/27/2019 1:57:33 PM
LastAccessTime    : 2/27/2019 8:57:33 AM
LastAccessTimeUtc : 2/27/2019 1:57:33 PM
LastWriteTime     : 2/27/2019 8:57:33 AM
LastWriteTimeUtc  : 2/27/2019 1:57:33 PM
Attributes        : Archive

Blogumla ilgili daha fazla ayrıntı.


1

Bir dizine giden Yol olup olmadığını kontrol etmek için şunu kullanın:

$pathToDirectory = "c:\program files\blahblah\"
if (![System.IO.Directory]::Exists($pathToDirectory))
{
 mkdir $path1
}

Bir dosyanın yolunun olup olmadığını kontrol etmek için @Mathias'ın önerdiği şeyi kullanın :

[System.IO.File]::Exists($pathToAFile)

0

Bu benim powershell acemi bunu yapmanın yolu

if ((Test-Path ".\Desktop\checkfile.txt") -ne "True") {
    Write-Host "Damn it"
} else {
    Write-Host "Yay"
}
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.