我正试图在powershell中创建一个小脚本,将文件和目录移动到正确的本地化位置。我发出了以下命令:
Get-ChildItem -Path '.list' | ForEach-Object { if ($($_.Name) -like '*[1]*') {
$file = $($_.Name)
$path = $($_.FullName)
echo "$file ==> $path"
Move-Item -Path $path -Destination .[1]}}
它检测到正确的文件和目录,但不会移动它们
然后我决定修改一下命令并创建硬链接:
Get-ChildItem -Path '.list' | ForEach-Object { if ($($_.Name) -like '*[1]*') {
$file = $($_.Name)
$path = $($_.FullName)
echo "$file ==> $path"
New-Item -Path ".``[1``]" -Name $file -Type HardLink -Target "$path"}}
我收到了以下响应(只切换到1个循环(:
[1] dir1 ==> D:test_movelist[1] dir1
New-Item:
Line |
5 | New-Item -Path ".``[1``]" -Name $file -Type HardLink -Target "$path …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Cannot find path 'D:test_movelist[1] dir1' because it does not exist.
无论是否具有管理权限,都会出现相同的错误。
我该怎么做才能让它发挥作用?
尝试以下操作:
Get-ChildItem -LiteralPath .list -File -Filter '*[1]*' | ForEach-Object {
$file = $_.Name
$path = $_.FullName
"$file ==> $path" # implicit `echo` aka `Write-Output`
New-Item -Force -Type HardLink `
-Path (Join-Path .[1] $file) `
-Target ([WildcardPattern]::Escape($path)) ` # !! see PowerShell Core comments below
-WhatIf
}
注意:上面命令中的-WhatIf
公共参数预览操作。一旦您确定操作将执行您想要的操作,请删除-WhatIf
-Filter '*[1]*'
预过滤Get-ChildItem
输出,使其仅包括名称包含子字符串[1]
逐字的文件,因为-Filter
参数使用文件系统本机通配符语言,而不将[
和]
视为元字符。- 相比之下,使用PowerShell更强大的通配符模式,
'*[1]*'
将匹配任何只包含1
的名称,因为[...]
被解释为字符集或范围。对于通配符匹配运算符-like
,您必须使用'*`[1`]*'
(用`
逐字解释的元字符的转义(来查找逐字的[1]
子字符串
- 相比之下,使用PowerShell更强大的通配符模式,
-File
将匹配项限制为文件,因为硬链接仅支持文件,不支持目录。-Path (Join-Path .[1] $file)
仅使用-Path
参数,而不是仅使用目录路径的-Path
参数和仅使用文件名的-Name
参数,这确保该参数被视为文字(逐字(路径,而不解释通配符元字符,如[
和]
。- 遗憾的是,将
-Path
与-Name
组合会导致-Path
参数被解释为通配符模式
- 遗憾的是,将
-Force
根据需要创建目标目录,但请注意,它也会替换任何预先存在的目标文件。Windows PowerShell:
([WildcardPattern]::Escape($path))
转义-Target
(也称为-Value
(参数(目标路径(,以便逐字处理,因为很遗憾,它被解释为通配符模式。未执行此转义会提示您看到的错误。洞穴:
在PowerShell[Core]7+中,GitHub提案#113136中批准了一项突破性的更改,以便更明智地将
-Target
参数视为文字(逐字(路径。在这种情况下,只需使用-Target $path
即可。然而,从PowerShell 7.2.2开始,这一更改尚未实现,不幸的是,针对包含
[
和]
的路径的操作目前已完全中断-请参阅GitHub问题#14534。- 从PowerShell 7.2.2开始,必须对进行两次转义(!(才能使其工作:
([WildcardPattern]::Escape([WildcardPattern]::Escape($path)))
- 从PowerShell 7.2.2开始,必须对进行两次转义(!(才能使其工作:
请注意,许多(但不是所有(文件处理cmdlet都提供了-LiteralPath
参数,以显式传递要从字面上(逐字逐句(获取的路径,而-Path
参数-通常是第一个位置参数的隐含参数-旨在接受通配符模式。
因此,您可以使Move-Item
的原始方法如下所示:
# Ensure that the target dir. exists.
# No escaping needed for -Path when not combined with -Name.
$null = New-Item -Type Directory -Path .[1] -Force
# Move the file, targeted with -LiteralPath, there.
# No escaping needed for -Destination.
Move-Item -LiteralPath $path -Destination .[1]
注意:与New-Item
不同,Move-Item
的-Force
不会按需创建目标目录。另一方面,与New-Item
的-Target
参数不同,Move-Item
的-Destination
更明智地从字面上(逐字逐句(解释其参数。