web-dev-qa-db-fra.com

Un meilleur moyen de vérifier si un chemin existe ou non dans PowerShell

Je n'aime pas la syntaxe de:

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

et

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

en particulier, il y a trop de parenthèses et pas très lisible lors de la vérification de "pas existé" pour une utilisation aussi commune. Quelle est la meilleure façon de faire cela?

Mise à jour: Ma solution actuelle consiste à utiliser des alias pour exist et not-exist comme expliqué ici .

Problème lié dans le référentiel PowerShell: https://github.com/PowerShell/PowerShell/issues/197

87
orad

Si vous souhaitez simplement une alternative à la syntaxe de la cmdlet, en particulier pour les fichiers, utilisez la méthode File.Exists() .NET:

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

Si, par contre, vous voulez un alias annulé à usage général pour Test-Path, voici comment procéder:

# 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 va maintenant se comporter exactement comme Test-Path, mais renvoie toujours le résultat opposé:

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

Comme vous l'avez déjà montré, le contraire est assez facile, alias exists à Test-Path:

PS C:\> New-Alias exists Test-Path
PS C:\> exists -Path "C:\Windows"
True
99
Mathias R. Jessen

La solution d'alias que vous avez publiée est astucieuse, mais je suis contre son utilisation dans les scripts, pour la même raison que je n'aime pas utiliser d'alias dans les scripts; cela a tendance à nuire à la lisibilité.

S'il s'agit de quelque chose que vous souhaitez ajouter à votre profil afin de pouvoir taper des commandes rapides ou de l'utiliser comme un shell, je pourrais voir que cela a du sens.

Vous pourriez envisager de créer une tuyauterie à la place:

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

Alternativement, pour l'approche négative, si cela convient à votre code, vous pouvez en faire une vérification positive, puis utilisez else pour le négatif:

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

Ajoutez les alias suivants. Je pense que ceux-ci devraient être disponibles dans PowerShell par défaut:

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

Avec cela, les instructions conditionnelles deviendront:

if (exist $path) { ... }

et

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

Une autre option consiste à utiliser IO.FileInfo, qui vous donne tant d’informations sur les fichiers que vous simplifiez la vie en utilisant simplement ce type:

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

Plus de détails sur mon blog.

2
VertigoRay