PowerShell文件存在检查返回false negative

时间:2018-02-20 14:18:50

标签: powershell

很简单,我需要使用PowerShell检查用户家庭驱动器中是否存在文件。该脚本将在一组机器上执行,因此路径需要是相对的。

当前输出:

# Create file named 'foo' in home dir
New-Item '~/foo'

# Check if the file exists
[System.IO.File]::Exists('~/foo')
# Returns false

列出文件显示它肯定存在:

ls '~/foo'

Directory: C:\Users\tom_n


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----           20/02/2018 14:13              0 foo

我错过了一些明显的东西吗?我还用一个具有实际大小的文件对此进行了测试,但也无济于事。

我很欣赏任何输入

3 个答案:

答案 0 :(得分:3)

<强> TL;博士

请勿使用~ - 使用$HOME 来引用当前用户的主目录,通常位于"..."内:< / p>

[System.IO.File]::Exists("$HOME/foo")

或者,最好使用PowerShell的Test-Path cmdlet:

Test-Path -LiteralPath "$HOME/foo"

注意:
* PowerShell和.NET类型接受/\ 可互换作为路径分隔符;为了实现潜在的跨平台兼容性,请选择/ *严格来说,由于"$HOME/foo"参数模式(命令行样式)中传递给Test-Path,因此在"..."中包含Write-Output $HOME/foo并不是必需的case(try "..."),但封装在~中是一个很好的习惯,因为它适用于更广泛的场景。 功能

PowerShell的~ 完全等同于 Unix上的~ (在POSIX-中)比如shell)并且可能无法按照您在PowerShell中的预期方式工作:

正如in this TechNet article [1] 所述,PowerShell中的 Set-location HKCU:\Software Set-Location ~ 指的是当前位置驱动器定义的归属位置提供商

  • 可能是也可能不是文件系统
  • 可能会或可能不会定义

在Windows上,请考虑以下使用注册表驱动程序提供程序的示例:

Set-Location : Home location for this provider is not set. To set the home location, call "(get-psprovider 'Registry').Home = 'path'".
...

产生以下错误

~

正如您所看到的,因为当前位置位于注册表提供商的驱动器上,~被解释为该提供商对家庭位置的想法,然而,不会被定义

另一个重要区别:

  • 在Unix上,~ shell 功能:必须使用 unquoted ,在这种情况下,它会扩展为完整的,文字的主目录由shell 之前目标命令看到路径,以便目标命令看到文字 path和不需要了解~ ,事实上,标准实用程序知道ls ~,您可以通过将ls '~'(确定)与~进行对比来验证(尝试列出文件/目录字面上名为~)。

  • 在PowerShell中,~ PowerShell驱动器提供程序功能 Get-ChildItem按原样传递给驱动程序提供程序~等cmdlet将findstr.exe解释为引用当前驱动器的家庭位置。 外部实用程序(例如,Windows上为~)和.NET Framework 遵循此约定,因此将~解释为 literal filename。

相比之下, automatic variable $HOME PowerShell相当于Unix ~ ,具有更大的灵活性:

虽然Unix $HOME必须未加引号才能扩展到用户的主目录,但可以引用PowerShell的自动[System.IO.File]变量在双引号字符串中(作为正常字符串扩展(插值)的一部分)。

最后, ~等.NET类型本身既不支持$HOME也不支持"$HOME/..." ,但使用$HOME它是 PowerShell ,确保在将路径字符串传递给.NET方法之前,将~替换为实际的文字主目录路径。

[1] Get-Help about_LocationsGet-Help about_Path_Syntax,关于此主题的官方帮助主题,应该包含有关{{1}}的信息,  但在撰写本文时不要。

答案 1 :(得分:2)

PowerShell CmdLet就是Test-Path

Test-Path '~/foo'

您可以将Windows文件表示与.NET类

一起使用
[System.IO.File]::Exists('.\foo')

答案 2 :(得分:1)

我认为问题是Exists()无法解析用~指定的主目录。尝试使用相对或绝对路径