PowerShell 如何将 Get-ChildItem 的输出转换为字符串数组

5

好的,我已经花费数小时进行研究并尝试了各种方法,但仍然无法使其正常运行。我需要从get-childitem创建一个string[]对象,并将其传递给Copy-Item-exclude参数。

难点在于我需要进行递归并且需要相对路径,所以这是我想出来的解决方案:

$((Get-ChildItem -Path $Dest -Recurse -File).FullName.TrimStart($Dest))

这将生成一个干净的现有文件列表,以相对路径呈现到$dest中。问题在于,如果我将此添加到copy-item -exclude参数中,它似乎会忽略它。在线上进一步研究表明,如果不是string[]类型,copy-item将忽略-exclude参数。
如果我检查上述命令返回的类型,我会得到System.Object[]。 我希望它是System.String[]或只是普通的String[]
如何将上述命令的输出转换为字符串数组?
为了清晰起见,使用copy-item的完整命令如下:
Copy-Item -Path (Join-Path $src "*") -Destination $dest -Recurse -Force -Exclude $((Get-ChildItem -Path $Dest -Recurse -File).FullName.TrimStart($Dest))

我的最终目标是递归复制文件而不会覆盖现有文件。


1
“-Exclude”(和“-Include”)仅支持文件名称模式,而不支持路径。但是,在此 GitHub 问题中正在讨论添加对路径的支持。 - mklement0
1
只是让你知道,TrimStart() 不应该这样使用。它需要一个字符数组,其中所有出现的字符都将从字符串开头删除,而不是要从开头删除的确切字符串;对于这种情况,您需要像 .FullName.Substring($Dest.Length) 这样的东西。显然,在这里 TrimStart($Dest) 对您起作用,这表明 $Dest 不包含尾部反斜杠。如果有尾部反斜杠,它可能会从 $Dest 长度之外的相对子路径中删除字符。 - Lance U. Matthews
Trimstart()不是你想象的那样。例如,这将导致一个空字符串:'ababab'.trimstart('ab')。 - js2010
3个回答

8
要从get-childitem cmdlet的名称中获得string[],请使用以下方法:
[string[]]$files = (Get-ChildItem).Name

这应该被标记为答案。 - Omzig

0

@mklement0 是正确的,-Exclude-Include 支持文件名模式(即 "*.txt"),而不是显式路径数组。

这听起来很像一个 XY 问题 ;-)

如果您只想递归复制文件而不覆盖它们,请使用 RobocopyMirror 开关。例如:

robocopy C:/Source C:/Dest /mir

编辑:

默认情况下,Copy-Item 命令会在复制时覆盖文件,并且没有任何开关可以避免这种情况。我通常建议使用 Robocopy,因为它真正简化了这样的操作,并且非常“强大”和可靠。

如果您的要求是“纯” PowerShell 版本,则必须将脚本拆分为两个部分:1. 获取所有文件的列表 2. 遍历文件并测试是否已经存在于目标位置之前再进行复制。

$SrcPath = "C:/Source"
$DestPath = "C:/Dest"

$SrcFiles = Get-ChildItem $SrcPath -Recurse

#Iterate through files testing:
$SrcFiles | ForEach-Object {
    #Calculate Destination File/Folder name/path
    $DestObj = $_.FullName.Replace($SrcPath, $DestPath)

    if(Test-Path -LiteralPath $DestObj)
    {
        #File already Exists
        Write-Host "File already Exists: $DestObj"
    }
    else
    {
        #File Does not exist - Copy
        Write-Host "File Does not Exist Copy: $DestObj"
        Copy-Item -Path $_ -Destination $DestObj
    }
}

谢谢您的回答。我知道RoboCopy,也知道它经常被提出作为解决方案。然而,我期望PowerShell能够轻松地复制文件而不覆盖现有文件。我不想启动第三方可执行文件,然后尝试在该可执行文件中处理错误处理和日志记录来完成一个非常简单的任务。 - Appleoddity
是的,默认情况下 Copy-Item 总是覆盖。请参见上面的编辑,我已经提供了一个完整的本地 PowerShell 解决方案。 - HAL9256

0

这将做你所说你想要的吗?但是,我认为可能并不是你问题的全部。

$((Get-ChildItem -Path $Dest -Recurse -File).FullName.Replace("$Dest",'.'))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接