O modalitate mai bună de a verifica dacă o cale există sau nu în PowerShell (Programare, Powershell)

orad a intrebat.

Pur și simplu nu-mi place sintaxa de:

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

și

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

mai ales că sunt prea multe paranteze și nu este foarte ușor de citit atunci când se verifică dacă „nu există” pentru o utilizare atât de comună. Care este o modalitate mai bună de a face acest lucru?

Actualizare: Soluția mea actuală este de a utiliza alias-uri pentru exist și not-exist așa cum se explică aici.

Problemă conexă în depozitul PowerShell: https://github.com/PowerShell/PowerShell/issues/1970

Comentarii

7 răspunsuri
Mathias R. Jessen

Dacă doriți doar o alternativă la sintaxa cmdletului, în special pentru fișiere, utilizați File.Exists() Metoda .NET:

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

Dacă, pe de altă parte, doriți un alias negat de uz general pentru Test-Path, , iată cum ar trebui să faceți acest lucru:

# 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 se va comporta acum exact ca Test-Path, , dar va returna întotdeauna rezultatul opus:

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

După cum ați arătat deja, opusul este destul de ușor, doar să se aliaseze exists la Test-Path:

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

Comentarii

  • Dacă $path este „special”, cum ar fi pe un furnizor Powershell (gândiți-vă la HKLM:SOFTWARE…), atunci acest lucru va eșua lamentabil. –  > Por Eris.
  • Întrebarea lui @Eris cere în mod special să se verifice dacă un fișier fișier există sau nu –  > Por Mathias R. Jessen.
  • Categoric, iar crearea unui nou cmdlet din mers este îngrijită. Aproape la fel de greu de întreținut ca un alias, dar totuși foarte frumos 🙂 –  > Por Eris.
  • Frumos! Cred că PS ar trebui să adauge suport nativ pentru acest lucru. –  > Por orad.
  • @orad Mă îndoiesc serios că îi vei convinge să facă asta. „Prea multe paranteze” este un foarte subiectiv și nu merită cu adevărat să te abați de la designul/specificația limbajului. FWIW, sunt de asemenea de acord cu construcția if/else propusă de @briantist ca o alternativă mai bună dacă urăști cu adevărat atât de mult parantezele: if(Test-Path $path){}else{ # do your thing } –  > Por Mathias R. Jessen.
briantist

Soluția de alias pe care ai postat-o este inteligentă, dar aș argumenta împotriva utilizării ei în scripturi, din același motiv pentru care nu-mi place să folosesc orice alias în scripturi; tinde să dăuneze lizibilității.

Dacă este ceva ce doriți să adăugați la profilul dvs. pentru a putea tasta comenzi rapide sau pentru a-l folosi ca un shell, atunci aș putea vedea că are sens.

În schimb, ați putea lua în considerare utilizarea pipe-urilor:

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

Alternativ, pentru abordarea negativă, dacă este adecvat pentru codul dvs., puteți face o verificare pozitivă, apoi utilizați else pentru cea negativă:

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

Comentarii

  • Îmi place canalizarea de aici, dar verificările propuse de dvs. pentru negativ sunt incorecte fără paranteze, sau va fi întotdeauna evaluat la False. Trebuie să procedați în felul următor if (-not ($path | Test-Path)) { ... }. –  > Por orad.
  • @orad ai dreptate! De fapt, acesta este un negativ al țevilor în acest caz. Am fost indus într-un fals sentiment de siguranță pentru că nu a aruncat o excepție, când, de fapt, nu reușea. Apelarea în modul original aruncă o excepție, ceea ce face mai ușor de detectat problema. –  > Por briantist.
orad

Adăugați următoarele pseudonime. Cred că acestea ar trebui să fie disponibile în PowerShell în mod implicit:

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

Cu aceasta, declarațiile condiționale se vor schimba în:

if (exist $path) { ... }

și

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

Comentarii

  • Dacă doriți ca echipa PowerShell să adauge un alias „exist”, trebuie să trimiteți o cerere de funcționalitate prin Microsoft Connect –  > Por Mathias R. Jessen.
  • Chiar dacă am răspuns eu însumi, accept răspunsul lui @mathias-r-jessen, deoarece acesta gestionează mai bine parametrii. –  > Por orad.
VertigoRay

O altă opțiune este de a utiliza IO.FileInfo care vă oferă atât de multe informații despre fișiere încât vă face viața mai ușoară doar folosind acest tip:

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


Mode              : -a----
VersionInfo       : File:             C:Tempfoo.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:Tempfoo.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

Mai multe detalii pe blogul meu.

David Bohbot

Acesta este modul meu de începător powershell de a face acest lucru

if ((Test-Path ".Desktopcheckfile.txt") -ne "True") {
    Write-Host "Damn it"
} else {
    Write-Host "Yay"
}

shaheen g

Pentru a verifica dacă există o Cale de acces la un director, utilizați aceasta:

$pathToDirectory = "c:program filesblahblah

if (![System.IO.Directory]::Exists($pathToDirectory))
{
 mkdir $path1
}

Pentru a verifica dacă există o Cărare către un fișier, utilizați ceea ce a sugerat @Mathias:

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

Vivek Raj
if (Test-Path C:DockerVolSelfCertSSL) {
    write-host "Folder already exists."
} else {
   New-Item -Path "C:DockerVol
 -Name "SelfCertSSL" -ItemType "directory"
}

Comentarii

  • Vă rugăm să adăugați mai multe explicații. –  > Por Paul Floyd.
  • Vă rugăm să nu postați doar codul ca răspuns, ci să oferiți și o explicație a ceea ce face codul dvs. și cum rezolvă problema din întrebare. Răspunsurile cu o explicație sunt de obicei mai utile și de o calitate mai bună și au mai multe șanse să atragă upvotes. –  > Por Pouria Hemati.