PowerShell文件存在性检查返回假阴性

PowerShell文件存在性检查返回假阴性,powershell,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

非常简单,我需要使用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
我是不是漏掉了什么明显的东西?我还用一个实际大小的文件对此进行了测试,但也没有用


我非常感谢PowerShell CmdLet为此提供的任何输入,即测试路径:

Test-Path '~/foo'
您可以将Windows文件表示与.NET类一起使用

[System.IO.File]::Exists('.\foo')

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

tl;博士

不要使用
~
-使用
$HOME
来引用当前用户的主目录,通常在
“…”内:

或者,最好使用PowerShell的
测试路径
cmdlet:

Test-Path -LiteralPath "$HOME/foo"
注:
*PowerShell和.NET类型可以互换地接受
/
\
作为路径分隔符;考虑到潜在的跨平台兼容性,请选择
/

*严格地说,由于
“$HOME/foo”
是在参数模式(命令行样式)下传递给
测试路径的,因此在这种情况下不需要使用
“…”
(尝试
编写输出$HOME/foo
),但使用
“…”
是一种良好的习惯,因为它适用于更广泛的场景。


PowerShell的
~
与Unix上的
~
不完全等效(在类似POSIX的shell中),并且可能无法按照您在PowerShell中期望的方式工作:

如[1]所述,
~
在PowerShell中指的是由当前位置的驱动器提供商定义的主位置,
,它:

  • 可能是也可能不是文件系统
  • 可以定义也可以不定义
在Windows上,考虑下面的示例,它使用注册表驱动程序提供程序:

Set-location HKCU:\Software
Set-Location ~
这将产生以下错误:

正如您所看到的,由于当前位置位于注册表提供程序的驱动器上,
~
被解释为该提供程序对主位置的想法,但碰巧没有定义主位置

另一个关键区别是:

  • 在Unix上,
    ~
    是一个shell功能:它必须使用无引号,在这种情况下,在目标命令看到路径之前,shell将它扩展到完整的文本主目录,这样目标命令就可以看到文本路径,而不需要知道
    ~
    ,事实上,标准实用程序不知道
    ~
    ,您可以通过对比
    ls~
    (确定)和
    ls'~'
    (尝试列出一个按字面命名的文件/dir
    ~
    )来验证这一点

  • 在PowerShell中,
    ~
    是PowerShell驱动器提供程序功能
    ~
    按原样传递给驱动器提供程序cmdlet,如
    Get ChildItem
    ,它们将
    ~
    解释为引用当前驱动器的主位置外部实用程序(例如,Windows上的
    findstr.exe
    )和.NET Framework不遵循此约定
    ,因此将
    ~
    解释为文本文件名


相比之下,是Unix的PowerShell等价物
~
,具有更大的灵活性:

虽然Unix
~
必须取消引号才能扩展到用户的主目录,但PowerShell的自动
$home
变量也可以在双引号字符串中引用(作为正常字符串扩展(插值)的一部分)


最后,.NET类型,如
[System.IO.File]
本身既不支持
~
也不支持
$HOME
,但通过使用
“$HOME/…”
,PowerShell确保在将路径字符串传递给.NET方法之前将
$HOME
替换为实际的文本主目录路径


[1] 而且,关于这个主题的官方帮助主题应该包含关于
~
,,
但在撰写本文时,请不要使用测试路径(例如:Test Path~\foo.txt)进行尝试。

为什么要进行向下投票?我的说法是正确的。您可以检查:[System.IO.Path]::GetFullPath(“~/asd”),它返回“currentdir/~/asd”。问题还没有解决。我只能猜测,但我想改变的两件事是,看看你是否发现了任何权威性的东西,比如从一开始我认为可能对你没有好处。此外,您的评论实际上为这些方法的工作原理增加了一个前置值。我会把它写进你的答案中。另外,如果OP在*nix意义上使用~的话,那么如果你的当前工作目录恰好是你的主目录,那么当前工作目录才是正确的答案。在任何其他目录中都是错误的。请注意。\Foo可能与~/Foo的路径相同,也可能不同。只有当你的pwd恰好是你的主目录时,它才会是相同的路径。获得一个更像*nix的命令行是Powershell最初的目标之一。关于
\foo
,@EBGreen,这一点很好。请注意,
~
可能指的是一个不是文件系统位置的位置,因为它相对于当前位置下的PS驱动器提供程序<相比之下,code>$HOME
总是指文件系统中用户的主目录。这应该是上帝的答案。
Set-location HKCU:\Software
Set-Location ~
Set-Location : Home location for this provider is not set. To set the home location, call "(get-psprovider 'Registry').Home = 'path'".
...