很简单,我需要使用 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
我在这里遗漏了一些明显的东西吗?我还使用具有实际大小的文件对此进行了测试,但也无济于事。
我很欣赏任何输入
最佳答案
tl;博士 :
请勿使用 ~
- 使用 $HOME
引用当前用户的主目录,通常在 "..."
内:
[System.IO.File]::Exists("$HOME/foo")
或者,最好使用 PowerShell 的
Test-Path
小命令:Test-Path -LiteralPath "$HOME/foo"
笔记:
* PowerShell 和 .NET 类型接受
/
和 \
可互换地作为路径分隔符;考虑到潜在的跨平台兼容性,请选择 /
.* 严格来说,自
"$HOME/foo"
传递给 Test-Path
在参数模式(命令行样式)中,包含在 "..."
中在这种情况下不需要(尝试 Write-Output $HOME/foo
),但包含在 "..."
中是一个养成的好习惯,因为它适用于更广泛的场景。PowerShell 的
~
不完全等同于 ~
在 Unix 上 (在类似 POSIX 的 shell 中)并且在 PowerShell 中可能无法按照您期望的方式工作:如解释 in this TechNet article [1],
~
在 PowerShell 中是指由当前位置的驱动器提供程序定义的主位置,哪一个:在 Windows 上,请考虑以下使用注册表驱动器提供程序的示例:
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'".
...
如您所见,因为当前位置位于注册表提供程序的驱动器上,
~
被解释为该提供商对家庭位置的想法,但是,恰好没有定义。一个额外的关键区别:
~
是一个 shell 特性:它必须不加引号地使用,在这种情况下,它会被 shell 扩展到完整的文字主目录。 , 在目标命令看到路径之前,这样目标命令看到的是文字路径并且不需要知道 ~
,事实上,标准实用程序并不知道 ~
,您可以通过对比 ls ~
来验证(好)与 ls '~'
(尝试列出字面上名为 ~
的文件/目录)。 ~
是 PowerShell 驱动器提供程序功能 :~
按原样传递给驱动器提供程序 cmdlet,例如 Get-ChildItem
他们解释 ~
指的是当前驱动器的主位置。 外部实用程序(例如,Windows 上的 findstr.exe
)和 .NET Framework 不遵循此约定 因此解释~
作为文字文件名。 相比之下, automatic variable
$HOME
是 PowerShell 等效于 Unix ~
,增加了灵活性:而 Unix
~
必须不加引号才能扩展到用户的主目录,PowerShell 的自动 $HOME
变量也可以在双引号字符串中引用(作为正常字符串扩展(插值)的一部分)。最后, .NET 类型,例如
[System.IO.File]
自己都不支持 ~
也不是 $HOME
,但通过使用 "$HOME/..."
PowerShell 确保 $HOME
在将路径字符串传递给 .NET 方法之前,将替换为实际的、文字主目录路径。[1]
Get-Help about_Locations
和 Get-Help about_Path_Syntax
,有关该主题的官方帮助主题,应包含有关 ~
的信息。 ,但在撰写本文时还没有。
关于PowerShell 文件存在性检查返回假阴性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48887329/