在PowerShell中检查路径是否存在的更好方法

时间:2015-08-08 01:01:31

标签: powershell

我只是不喜欢语法:

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

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

特别是在检查“不存在”这种常见用途时,括号太多且不易读。有什么更好的方法呢?

更新:我目前的解决方案是按照here的说明使用existnot-exist的别名。

  

PowerShell存储库中的相关问题:https://github.com/PowerShell/PowerShell/issues/1970

8 个答案:

答案 0 :(得分:90)

如果您只想要替代cmdlet语法,特别是文件,请使用File.Exists() .NET方法:

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

另一方面,如果您想要Test-Path的通用否定别名,请按以下步骤操作:

# 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现在将完全表现为Test-Path,但总是会返回相反的结果:

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

正如您已经展示过的那样,相反的情况非常简单,只需将exists替换为Test-Path

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

答案 1 :(得分:23)

你发布的别名解决方案很聪明,但我反对在脚本中使用它,因为我不喜欢在脚本中使用任何别名;它往往会损害可读性。

如果这是你要添加到个人资料中的内容,那么你可以输入快速命令或将其用作shell,那么我可以看出它有意义。

您可以考虑使用管道:

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

或者,对于否定方法,如果适合您的代码,您可以将其作为肯定检查,然后使用else作为否定:

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

答案 2 :(得分:7)

添加以下别名。我认为这些应该默认在PowerShell中提供:

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

这样,条件语句将变为:

if (exist $path) { ... }

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

答案 3 :(得分:1)

另一种选择是使用 binding.getRoot().animate().rotation(-5).setDuration(500).setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { binding.getRoot().animate().rotation(5).setDuration(1000).setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { binding.getRoot().animate().rotation(0).setDuration(500); } }); } }); ,它为您提供了很多文件信息,仅使用以下类型即可使工作更轻松:

IO.FileInfo

More details on my blog.

答案 4 :(得分:1)

要检查目录是否存在路径,请使用以下命令:

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

要检查文件路径是否存在,请使用@Mathias的建议:

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

答案 5 :(得分:1)

这是我的Powershell新手实现方法

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

答案 6 :(得分:0)

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

答案 7 :(得分:0)

在查看@Mathias R. Jessen 的出色回答后,我突然想到您不需要创建两个新函数。相反,您可以围绕原生 Test-Path 函数创建一个同名的包装器,添加一个 -Not 开关:

$TestPathCmd = Get-Command Test-Path
$TestPathCmdMetaData = New-Object System.Management.Automation.CommandMetadata $TestPathCmd
$Binding = [System.Management.Automation.ProxyCommand]::GetCmdletBindingAttribute($TestPathCmdMetaData)
$Params  = [System.Management.Automation.ProxyCommand]::GetParamBlock($TestPathCmdMetaData)

$Params += ', [Switch]${Not}'
$WrappedCommand = {
    $PSBoundParameters.Remove('Not') | Out-Null
    [Bool]($Not.ToBool() -bxor (Microsoft.PowerShell.Management\Test-Path @PSBoundParameters))
}

${Function:Test-Path} = '{0} Param({1}) {2}' -f $Binding,$Params,$WrappedCommand

例如:

Test-Path -Path 'C:\Temp'      # True
Test-Path -Path 'C:\Temp' -Not # False
Test-Path -Path 'C:\Txmp'      # False
Test-Path -Path 'C:\Txmp' -Not # True

这有几个优点:

  1. 熟悉的语法:当您不使用自定义开关时,语法与本机命令相同,当您使用时,所发生的事情非常直观,这意味着用户的认知负担更少,共享时的兼容性更高。< /li>
  2. 因为包装器在后台调用本机函数,所以它可以在本机函数执行的任何地方工作,例如:
    Test-Path -Path 'HKLM:\SOFTWARE'      # True
    Test-Path -Path 'HKLM:\SOFTWARE' -Not # False
    Test-Path -Path 'HKLM:\SXFTWARE'      # False
    Test-Path -Path 'HKLM:\SXFTWARE' -Not # True
    
相关问题