重命名项目失败并显示“无法重命名,因为 'C:\Folder\ Example App Folder ' 处的项目不存在
Rename-Item fails with 'Cannot rename because item at 'C:\Folder\ Example App Folder ' does not exist
我有一个文件夹,其中有 100 个子文件夹和文件,这些子文件夹中的文件名称带有前导和尾随空格。这些文件夹和文件是使用 Node JS 应用程序创建的。我现在需要从文件夹和文件的文件名中删除前导和尾随空格。
我发现这个 script 似乎是为此目的而建造的。
如果我使用该函数创建 files/folders 并在同一博客中提到前导空格,脚本可以重命名它们。
但是,它不适用于使用节点 JS 应用程序创建的 files/folders。重命名 folder/file 时失败并显示 -
Rename-Item : Cannot rename because item at 'C:\Folder\ Example App Folder ' does not exist.
At C:\renamefileswithspaces.ps1:25 char:13
+ Rename-Item -LiteralPath $_.fullname -NewName (“{0}{1}{2} ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Rename-Item], PSInvalidOperationException
+ FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.RenameItemCommand
如果我 运行 仅针对一个文件夹(在脚本之外)执行以下 cmdlet,它会失败并出现相同的错误 -
$f = Get-ChildItem -Path 'C:\Folder' -Filter "*Example*"
Rename-Item -LiteralPath $f.FullName -NewName $f.Name.Trim()
Rename-Item : Cannot rename because item at 'C:\Folder\ Example App Folder ' does not exist.
At line:1 char:1
+ Rename-Item -LiteralPath $f.FullName -NewName $f.Name.Trim()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Rename-Item], PSInvalidOperationException
+ FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.RenameItemCommand
为什么 Rename-Item 对于使用应用创建的 files/folders 失败,而对于使用 PowerShell 创建的 files/folders 有效?
编辑:运行 Windows Server 2016 Standard。 PowerShell 版本 - 5.1.14393.3866
编辑 2:从 here 更新到 PowerShell 7.1.4,问题仍然存在。
作为解决方法,您可以使用 DirectoryInfo 和 FileInfo 对象都具有的 .MoveTo()
方法。
对我来说这很有效:
# get both files and directories
Get-ChildItem -Path 'C:\Folder' -Recurse |
Where-Object { $_.BaseName -ne $_.BaseName.Trim() } |
ForEach-Object {
# the DirectoryName property does not exist on DirectoryInfo objects..
$path = [System.IO.Path]::GetDirectoryName($_.FullName)
$trimmed = Join-Path -Path $path -ChildPath ('{0}{1}' -f $_.BaseName.Trim(), $_.Extension.Trim())
$_.MoveTo($trimmed)
}
尾随 文件/目录名称中的空格有问题 on Windows(除非文件扩展名也存在,并且尾随空格仅在 base 文件名中):
PowerShell、.NET、cmd.exe
和文件资源管理器:
不能创建具有此类名称的项目,因为给定的名称总是有尾随空格 removed用过。
不能复制、重命名或删除此类项目(如果它们是通过其他方式创建的,例如Node.js - 见下文) , 出于同样的原因:给定的名称/路径删除了尾随空格,并且查找生成的修改后的名称失败。
可以 枚举 此类项目(Get-ChildItem
、[System.IO.Directory]::EnumerateDirectories()
、dir
、文件资源管理器中的文件列表) .
虽然 文件系统本身 允许这样的名称,但创建它们显然不是一个好主意。
Node.js 允许您创建它们,但幸运的是还允许您稍后将它们定位为重命名或删除。
因此,解决方法是也使用 Node.js 进行重命名;例如:
node -e "fs.renameSync(' Example App directory ', 'Example App directory')"
这是一个独立的示例,它使用临时文件夹枚举所有子目录,并在需要时通过删除名称中的前导和尾随空格来重命名它们:
# Switch to a temporary directory.
Push-Location -ea Stop ($tmpDir = (New-Item -Type Directory -Force (Join-Path $env:TEMP/ $PID)).FullName)
try {
# Create a test directory whose name has trailing (and leading) spaces.
# Note:
# * You cannot do this with PowerShell / cmd.exe commands.
# * To delete or rename such a directory, use Node.js too:
# node -e "fs.rmdirSync(' Example App directory ')"
# node -e "fs.renameSync(' Example App directory ', 'Example App directory')"
node -e "fs.mkdirSync(' Example App directory ')"
if ($LASTEXITCODE) { throw }
# Create another directory, but without leading or trailing whitespace.
$null = New-Item -Type Directory 'Example without surrounding spaces'
# Enumerate all directories and rename them, if needed,
# by trimming leading and trailing whitespace.
# Note: The Get-ChildItem call is enclosed in (...) to guard against renamed directorys
# re-entering the enumeration.
(Get-ChildItem -LiteralPath . -Directory -Filter *) | ForEach-Object {
# Determine the full path with the name part trimmed.
$trimmedPath = Join-Path (Split-Path -LiteralPath $_.FullName) ($_.BaseName.Trim() + $_.Extension.Trim())
if ($trimmedPath -ne $_.FullName) { # Trimming is needed.
Write-Verbose -vb "Renaming '$($_.FullName)' to '$($trimmedPath)'..."
# Perform the renaming via Node.js
node -e ("fs.renameSync('{0}', '{1}')" -f ($_.FullName -replace "[\']", '$0'), ($trimmedPath -replace "[\']", '$0'))
if ($LASTEXITCODE) { Write-Error "Renaming '$($_.FullName)' to '$($trimmedPath)' failed with exit code $LASTEXITCODE." }
}
else { # Trimming not needed.
Write-Verbose -vb "Name has no leading or trailing spaces: '$($_.FullName)'"
}
}
Write-Verbose -vb "Names after:"
(Get-ChildItem).Name.ForEach({"[$_]"})
}
finally {
# Clean up.
Pop-Location; Remove-Item $tmpDir -Recurse
}
示例输出:
VERBOSE: Renaming 'C:\Users\jdoe\AppData\Local\Temp12\ Example App directory ' to 'C:\Users\jdoe\AppData\Local\Temp12\Example App directory'...
VERBOSE: Name has no leading or trailing spaces: 'C:\Users\jdoe\AppData\Local\Temp12\Example without surrounding spaces'
VERBOSE: Names after:
[Example App directory]
[Example without surrounding spaces]
注:
- 为每个输入目录调用 Node.js CLI
node
的方法效率不高,但对于一次性清理操作可能无关紧要。
我有一个文件夹,其中有 100 个子文件夹和文件,这些子文件夹中的文件名称带有前导和尾随空格。这些文件夹和文件是使用 Node JS 应用程序创建的。我现在需要从文件夹和文件的文件名中删除前导和尾随空格。
我发现这个 script 似乎是为此目的而建造的。
如果我使用该函数创建 files/folders 并在同一博客中提到前导空格,脚本可以重命名它们。
但是,它不适用于使用节点 JS 应用程序创建的 files/folders。重命名 folder/file 时失败并显示 -
Rename-Item : Cannot rename because item at 'C:\Folder\ Example App Folder ' does not exist.
At C:\renamefileswithspaces.ps1:25 char:13
+ Rename-Item -LiteralPath $_.fullname -NewName (“{0}{1}{2} ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Rename-Item], PSInvalidOperationException
+ FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.RenameItemCommand
如果我 运行 仅针对一个文件夹(在脚本之外)执行以下 cmdlet,它会失败并出现相同的错误 -
$f = Get-ChildItem -Path 'C:\Folder' -Filter "*Example*"
Rename-Item -LiteralPath $f.FullName -NewName $f.Name.Trim()
Rename-Item : Cannot rename because item at 'C:\Folder\ Example App Folder ' does not exist.
At line:1 char:1
+ Rename-Item -LiteralPath $f.FullName -NewName $f.Name.Trim()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Rename-Item], PSInvalidOperationException
+ FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.RenameItemCommand
为什么 Rename-Item 对于使用应用创建的 files/folders 失败,而对于使用 PowerShell 创建的 files/folders 有效?
编辑:运行 Windows Server 2016 Standard。 PowerShell 版本 - 5.1.14393.3866
编辑 2:从 here 更新到 PowerShell 7.1.4,问题仍然存在。
作为解决方法,您可以使用 DirectoryInfo 和 FileInfo 对象都具有的 .MoveTo()
方法。
对我来说这很有效:
# get both files and directories
Get-ChildItem -Path 'C:\Folder' -Recurse |
Where-Object { $_.BaseName -ne $_.BaseName.Trim() } |
ForEach-Object {
# the DirectoryName property does not exist on DirectoryInfo objects..
$path = [System.IO.Path]::GetDirectoryName($_.FullName)
$trimmed = Join-Path -Path $path -ChildPath ('{0}{1}' -f $_.BaseName.Trim(), $_.Extension.Trim())
$_.MoveTo($trimmed)
}
尾随 文件/目录名称中的空格有问题 on Windows(除非文件扩展名也存在,并且尾随空格仅在 base 文件名中):
PowerShell、.NET、cmd.exe
和文件资源管理器:
不能创建具有此类名称的项目,因为给定的名称总是有尾随空格 removed用过。
不能复制、重命名或删除此类项目(如果它们是通过其他方式创建的,例如Node.js - 见下文) , 出于同样的原因:给定的名称/路径删除了尾随空格,并且查找生成的修改后的名称失败。
可以 枚举 此类项目(
Get-ChildItem
、[System.IO.Directory]::EnumerateDirectories()
、dir
、文件资源管理器中的文件列表) .
虽然 文件系统本身 允许这样的名称,但创建它们显然不是一个好主意。
Node.js 允许您创建它们,但幸运的是还允许您稍后将它们定位为重命名或删除。
因此,解决方法是也使用 Node.js 进行重命名;例如:
node -e "fs.renameSync(' Example App directory ', 'Example App directory')"
这是一个独立的示例,它使用临时文件夹枚举所有子目录,并在需要时通过删除名称中的前导和尾随空格来重命名它们:
# Switch to a temporary directory.
Push-Location -ea Stop ($tmpDir = (New-Item -Type Directory -Force (Join-Path $env:TEMP/ $PID)).FullName)
try {
# Create a test directory whose name has trailing (and leading) spaces.
# Note:
# * You cannot do this with PowerShell / cmd.exe commands.
# * To delete or rename such a directory, use Node.js too:
# node -e "fs.rmdirSync(' Example App directory ')"
# node -e "fs.renameSync(' Example App directory ', 'Example App directory')"
node -e "fs.mkdirSync(' Example App directory ')"
if ($LASTEXITCODE) { throw }
# Create another directory, but without leading or trailing whitespace.
$null = New-Item -Type Directory 'Example without surrounding spaces'
# Enumerate all directories and rename them, if needed,
# by trimming leading and trailing whitespace.
# Note: The Get-ChildItem call is enclosed in (...) to guard against renamed directorys
# re-entering the enumeration.
(Get-ChildItem -LiteralPath . -Directory -Filter *) | ForEach-Object {
# Determine the full path with the name part trimmed.
$trimmedPath = Join-Path (Split-Path -LiteralPath $_.FullName) ($_.BaseName.Trim() + $_.Extension.Trim())
if ($trimmedPath -ne $_.FullName) { # Trimming is needed.
Write-Verbose -vb "Renaming '$($_.FullName)' to '$($trimmedPath)'..."
# Perform the renaming via Node.js
node -e ("fs.renameSync('{0}', '{1}')" -f ($_.FullName -replace "[\']", '$0'), ($trimmedPath -replace "[\']", '$0'))
if ($LASTEXITCODE) { Write-Error "Renaming '$($_.FullName)' to '$($trimmedPath)' failed with exit code $LASTEXITCODE." }
}
else { # Trimming not needed.
Write-Verbose -vb "Name has no leading or trailing spaces: '$($_.FullName)'"
}
}
Write-Verbose -vb "Names after:"
(Get-ChildItem).Name.ForEach({"[$_]"})
}
finally {
# Clean up.
Pop-Location; Remove-Item $tmpDir -Recurse
}
示例输出:
VERBOSE: Renaming 'C:\Users\jdoe\AppData\Local\Temp12\ Example App directory ' to 'C:\Users\jdoe\AppData\Local\Temp12\Example App directory'...
VERBOSE: Name has no leading or trailing spaces: 'C:\Users\jdoe\AppData\Local\Temp12\Example without surrounding spaces'
VERBOSE: Names after:
[Example App directory]
[Example without surrounding spaces]
注:
- 为每个输入目录调用 Node.js CLI
node
的方法效率不高,但对于一次性清理操作可能无关紧要。