如何让 Get-ChildItem 处理不间断的路径 space
How to get Get-ChildItem to handle path with non-breaking space
我有以下适用于大多数文件的代码。输入文件 (FoundLinks.csv) 是一个 UTF-8 文件,每行一个文件路径。它是我需要处理的特定驱动器上文件的完整路径。
$inFiles = @()
$inFiles += @(Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv")
foreach ($inFile in $inFiles) {
Write-Host("Processing: " + $inFile)
$objFile = Get-ChildItem -LiteralPath $inFile
New-Object PSObject -Prop @{
FullName = $objFile.FullName
ModifyTime = $objFile.LastWriteTime
}
}
但即使我使用了 -LiteralPath,它仍然无法处理文件名中包含不间断 space 的文件。
Processing: q:\Executive\CLC\Budget\Co 2018 Budget - TO Bob (GA Prophix).xlsx
Get-ChildItem : Cannot find path 'Q:\Executive\CLC\Budget\Co 2018 Budget - TO Bob (GA Prophix).xlsx'
because it does not exist.
At ListFilesWithModifyTime.ps1:6 char:29
+ $objFile = Get-ChildItem <<<< -LiteralPath $inFile
+ CategoryInfo : ObjectNotFound: (Q:\Executive\CL...A Prophix).xlsx:String) [Get-ChildItem], ItemNotFound
Exception
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
我知道我的输入文件在路径中有不间断的 space,因为我可以在记事本中打开它,复制有问题的路径,粘贴到 Word 中,然后打开段落标记。它显示了一个正常的 space,然后是 2018 年之前的 NBSP。
PowerShell 没有读入 NBSP 吗?我把它错误地传递给了-LiteralPath吗?我已经无计可施了。我看到了 ,但在那种情况下,他们在脚本中以文字形式提供路径,所以我看不出如何使用该方法。
我也尝试过:-Encoding UTF8
Get-Content 参数,但没有区别。
我什至不确定如何检查代码中的 $inFile 以确认它是否仍然包含 NBSP。
感谢任何帮助摆脱困境的帮助!
确认 $inFile 有 NBSP
谢谢大家!根据@TheMadTechnician,我已经更新了这样的代码,并将我的输入文件减少到只有一个有问题的文件。
$inFiles = @()
$inFiles += @(Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv" -Encoding UTF8)
foreach ($inFile in $inFiles) {
Write-Host("Processing: " + $inFile)
# list out all chars to confirm it has an NBSP
$inFile.ToCharArray()|%{"{0} -> {1}" -f $_,[int]$_}
$objFile = Get-ChildItem -LiteralPath $inFile
New-Object PSObject -Prop @{
FullName = $objFile.FullName
ModifyTime = $objFile.LastWriteTime
}
}
所以现在我可以确认 $inFile 实际上仍然包含 NBSP,就像它被传递给 Get-ChildItem 一样。然而 Get-ChildItem 说该文件不存在。
更多我尝试过的:
- 如果我使用 Get-Item 而不是 Get-ChildItem,则相同
- 如果我使用 -Path 而不是 -LiteralPath,则相同
- Windows explorer 和 Excel 可以成功处理文件。
我在 Windows 7 机器上,Powershell 2。
再次感谢大家的回复!
Get-ChildItem
用于列出 children 所以你会给它一个目录,但看起来你给它一个文件,所以当它说它找不到路径,这是因为它找不到具有该名称的目录。
相反,您可能希望使用 Get-Item -LiteralPath
来获取每个单独的项目(这与您在其父项上 运行 Get-ChildItem
时获得的项目相同。
我认为换入 Get-Item
会使您的代码按原样工作。
经过测试,我认为以上内容实际上是错误的,对此深表歉意,但我会保留以下内容以防它有帮助,即使它可能无法解决您眼前的问题。
但让我们看一下如何使用管道对其进行简化。
首先,您从一个空数组开始,然后调用可能已经 returns 一个数组的命令 (Get-Content
),将其包装在一个数组中,然后将其连接到空数组一.
你可以这样做:
$inFiles = Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv"
是的,$inFiles
有可能只包含一个项目而不是数组。
不过好在 foreach
一点都不介意!
你可以做这样的事情并且它很管用:
foreach ($string in "a literal single string") {
Write-Host $string
}
但是 Get-Item
(和 Get-ChildItem
就此而言)接受管道输入,因此他们接受多个项目。
这意味着你可以这样做:
$inFiles = Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv" | Get-Item
foreach ($inFile in $inFiles) {
Write-Host("Processing: " + $inFile)
New-Object PSObject -Prop @{
FullName = $inFile.FullName
ModifyTime = $inFile.LastWriteTime
}
}
但不仅如此,还有一个用于处理项目的管道感知 cmdlet,称为 ForEach-Object
,您向其传递一个 [ScriptBlock]
,其中 $_
表示当前项目,所以我们可以这样做:
Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv" |
Get-Item |
ForEach-Object -Process {
Write-Host("Processing: " + $_)
New-Object PSObject -Prop @{
FullName = $_.FullName
ModifyTime = $_.LastWriteTime
}
}
全部在一个管道中!
但是,您正在创建一个具有您想要的 2 个属性的新对象。
PowerShell 有一个名为 Select-Object
的漂亮 cmdlet,它接受一个输入对象和 returns 一个仅包含您想要的属性的新对象;这将使语法更清晰:
Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv" |
Get-Item |
Select-Object -Property FullName,LastWriteTime
这就是将真实对象从一个命令传递到另一个命令的管道的威力。
我意识到最后一个例子不会将处理消息写入屏幕,但是如果需要,您可以重新添加它:
Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv" |
Get-Item |
ForEach-Object -Process {
Write-Host("Processing: " + $_)
$_ | Select-Object -Property FullName,LastWriteTime
}
但您可能还考虑到许多 cmdlet 支持详细输出,并尝试将 -Verbose
添加到您现有的一些 cmdlet。遗憾的是,它在这种情况下并没有真正的帮助。
最后一点,当您通过管道将项目传递给文件系统 cmdlet 时,它们绑定的参数实际上是 -LiteralPath
,而不是 -Path
,因此您的特殊字符仍然是安全的。
尚不清楚为什么 Sandra 的代码不起作用:PowerShell v2+ 能够检索路径包含非 ASCII 字符的文件;也许涉及具有不同字符编码的非 NTFS 文件系统?
但是,以下 解决方法 结果证明是有效的:
$objFile = Get-ChildItem -Path ($inFile -replace ([char] 0xa0), '?')
想法是替换不间断的 space 字符。 (Unicode U+00A0
;hex.0xa
)在输入文件路径中带有通配符?
,表示任意单个字符.
为了Get-ChildItem
执行通配符匹配,必须使用-Path
而不是-LiteralPath
(注意-Path
实际上是默认值,如果你传递路径参数 positionally,作为第一个参数)。
假设,基于通配符的路径可以匹配 多个 文件;如果是这种情况,则必须检查各个匹配项以确定在 ?
.
[=41= 的位置具有不间断 space 的特定匹配项]
我有以下适用于大多数文件的代码。输入文件 (FoundLinks.csv) 是一个 UTF-8 文件,每行一个文件路径。它是我需要处理的特定驱动器上文件的完整路径。
$inFiles = @()
$inFiles += @(Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv")
foreach ($inFile in $inFiles) {
Write-Host("Processing: " + $inFile)
$objFile = Get-ChildItem -LiteralPath $inFile
New-Object PSObject -Prop @{
FullName = $objFile.FullName
ModifyTime = $objFile.LastWriteTime
}
}
但即使我使用了 -LiteralPath,它仍然无法处理文件名中包含不间断 space 的文件。
Processing: q:\Executive\CLC\Budget\Co 2018 Budget - TO Bob (GA Prophix).xlsx
Get-ChildItem : Cannot find path 'Q:\Executive\CLC\Budget\Co 2018 Budget - TO Bob (GA Prophix).xlsx'
because it does not exist.
At ListFilesWithModifyTime.ps1:6 char:29
+ $objFile = Get-ChildItem <<<< -LiteralPath $inFile
+ CategoryInfo : ObjectNotFound: (Q:\Executive\CL...A Prophix).xlsx:String) [Get-ChildItem], ItemNotFound
Exception
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
我知道我的输入文件在路径中有不间断的 space,因为我可以在记事本中打开它,复制有问题的路径,粘贴到 Word 中,然后打开段落标记。它显示了一个正常的 space,然后是 2018 年之前的 NBSP。
PowerShell 没有读入 NBSP 吗?我把它错误地传递给了-LiteralPath吗?我已经无计可施了。我看到了
我也尝试过:-Encoding UTF8
Get-Content 参数,但没有区别。
我什至不确定如何检查代码中的 $inFile 以确认它是否仍然包含 NBSP。
感谢任何帮助摆脱困境的帮助!
确认 $inFile 有 NBSP
谢谢大家!根据@TheMadTechnician,我已经更新了这样的代码,并将我的输入文件减少到只有一个有问题的文件。
$inFiles = @()
$inFiles += @(Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv" -Encoding UTF8)
foreach ($inFile in $inFiles) {
Write-Host("Processing: " + $inFile)
# list out all chars to confirm it has an NBSP
$inFile.ToCharArray()|%{"{0} -> {1}" -f $_,[int]$_}
$objFile = Get-ChildItem -LiteralPath $inFile
New-Object PSObject -Prop @{
FullName = $objFile.FullName
ModifyTime = $objFile.LastWriteTime
}
}
所以现在我可以确认 $inFile 实际上仍然包含 NBSP,就像它被传递给 Get-ChildItem 一样。然而 Get-ChildItem 说该文件不存在。
更多我尝试过的:
- 如果我使用 Get-Item 而不是 Get-ChildItem,则相同
- 如果我使用 -Path 而不是 -LiteralPath,则相同
- Windows explorer 和 Excel 可以成功处理文件。
我在 Windows 7 机器上,Powershell 2。
再次感谢大家的回复!
Get-ChildItem
用于列出 children 所以你会给它一个目录,但看起来你给它一个文件,所以当它说它找不到路径,这是因为它找不到具有该名称的目录。
相反,您可能希望使用 Get-Item -LiteralPath
来获取每个单独的项目(这与您在其父项上 运行 Get-ChildItem
时获得的项目相同。
我认为换入 Get-Item
会使您的代码按原样工作。
经过测试,我认为以上内容实际上是错误的,对此深表歉意,但我会保留以下内容以防它有帮助,即使它可能无法解决您眼前的问题。
但让我们看一下如何使用管道对其进行简化。
首先,您从一个空数组开始,然后调用可能已经 returns 一个数组的命令 (Get-Content
),将其包装在一个数组中,然后将其连接到空数组一.
你可以这样做:
$inFiles = Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv"
是的,$inFiles
有可能只包含一个项目而不是数组。
不过好在 foreach
一点都不介意!
你可以做这样的事情并且它很管用:
foreach ($string in "a literal single string") {
Write-Host $string
}
但是 Get-Item
(和 Get-ChildItem
就此而言)接受管道输入,因此他们接受多个项目。
这意味着你可以这样做:
$inFiles = Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv" | Get-Item
foreach ($inFile in $inFiles) {
Write-Host("Processing: " + $inFile)
New-Object PSObject -Prop @{
FullName = $inFile.FullName
ModifyTime = $inFile.LastWriteTime
}
}
但不仅如此,还有一个用于处理项目的管道感知 cmdlet,称为 ForEach-Object
,您向其传递一个 [ScriptBlock]
,其中 $_
表示当前项目,所以我们可以这样做:
Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv" |
Get-Item |
ForEach-Object -Process {
Write-Host("Processing: " + $_)
New-Object PSObject -Prop @{
FullName = $_.FullName
ModifyTime = $_.LastWriteTime
}
}
全部在一个管道中!
但是,您正在创建一个具有您想要的 2 个属性的新对象。
PowerShell 有一个名为 Select-Object
的漂亮 cmdlet,它接受一个输入对象和 returns 一个仅包含您想要的属性的新对象;这将使语法更清晰:
Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv" |
Get-Item |
Select-Object -Property FullName,LastWriteTime
这就是将真实对象从一个命令传递到另一个命令的管道的威力。
我意识到最后一个例子不会将处理消息写入屏幕,但是如果需要,您可以重新添加它:
Get-Content -Path "C:\Users\sw_admin\FoundLinks.csv" |
Get-Item |
ForEach-Object -Process {
Write-Host("Processing: " + $_)
$_ | Select-Object -Property FullName,LastWriteTime
}
但您可能还考虑到许多 cmdlet 支持详细输出,并尝试将 -Verbose
添加到您现有的一些 cmdlet。遗憾的是,它在这种情况下并没有真正的帮助。
最后一点,当您通过管道将项目传递给文件系统 cmdlet 时,它们绑定的参数实际上是 -LiteralPath
,而不是 -Path
,因此您的特殊字符仍然是安全的。
尚不清楚为什么 Sandra 的代码不起作用:PowerShell v2+ 能够检索路径包含非 ASCII 字符的文件;也许涉及具有不同字符编码的非 NTFS 文件系统?
但是,以下 解决方法 结果证明是有效的:
$objFile = Get-ChildItem -Path ($inFile -replace ([char] 0xa0), '?')
想法是替换不间断的 space 字符。 (Unicode
U+00A0
;hex.0xa
)在输入文件路径中带有通配符?
,表示任意单个字符.为了
Get-ChildItem
执行通配符匹配,必须使用-Path
而不是-LiteralPath
(注意-Path
实际上是默认值,如果你传递路径参数 positionally,作为第一个参数)。假设,基于通配符的路径可以匹配 多个 文件;如果是这种情况,则必须检查各个匹配项以确定在
[=41= 的位置具有不间断 space 的特定匹配项]?
.