Powershell Copy-Item对于相同路径给出2种不同结果

斯克兰博

问题


我正在使用Powershell编写部署脚本。使用Copy-Item命令不会在两次运行之间提供相同的结果,即使使用相同的数据也是如此。(似乎不是幂等的)

有关我的意思的示例,请参见下面的结果。我意识到我可以C:\products在复制“新”版本之前删除其中的文件,但是我对这在Powershell中是否是预期的行为感到好奇。(我假设是这样)

我宁愿学习“正确”的使用方式,也Copy-Item不要因为缺乏知识而乱砍。

我尝试使用target\*path代替,target但是这将我的lib文件夹分解到的根中showcase,即使带该-Recurse标志我也没想到

C:\products
  - showcase
    - showcase.jar
    - logback.jar
    - foo.jar
    - junit.jar
    - etc, etc

我也对这里的文档(特别是示例7,10和11)感到困惑,因为7使用了该-Recurse标志,而11使用了该标志。同时,示例10表示:

如果scripts文件夹在子文件夹中包含文件,则这些子文件夹将在其文件树完好无损的情况下被复制。

但也不会指定任何递归标志。


结果

部署前

C:\products
  - backup

初始部署

C:\products
  - showcase
    - showcase.jar
    - lib
      - <dependencies for showcase.jar>
  - backup
    <empty>
# Expected, as there wasn't a prior deployment yet.

第二次部署

C:\products
  - showcase
    - showcase.jar
    - lib
      - <dependencies for showcase.jar>
    - target
      - showcase.jar
      - lib
        - <dependencies for inner showcase.jar>
  - backup
    - showcase
      - showcase.jar
      - lib
        - <dependencies for "old" showcase.jar>
  # Expected, the old version was backed up

部署脚本及其调用方式

./deploy.ps1 -hostname foobar (it's a remote server)

deploy.ps1

param( [String]$hostname, [switch]$debug )

$folder_to_copy = "target"
$init_file = "./init.ps1"

function Backup-Binary ( [String]$source, [String]$name, [String]$dest ) {

    $FullyQualifiedSourcePath = "$source\$name"

    if (Test-Path $FullyQualifiedSourcePath) {
        Write-Host "Backing up $FullyQualifiedSourcePath to the destination $dest"
        Copy-Item -Recurse -Force -Path $FullyQualifiedSourcePath -Destination $dest -ErrorAction Stop
    } else {
        Write-Output "Directory $FullyQualifiedSourcePath didn't exist. May be an initial deployment. Continuing with deployment."
    }

}

function Verify-Env ([String]$env_var) {
     $check = [Environment]::GetEnvironmentVariable($env_var)
     if ($check -eq $null) {
         Write-Error "$env_var environment variable doesn't exist. Exiting program."
         exit 1
     }
}

function Deploy-Local {

    # Checks that the given string exists as an Environment variable
    Verify-Env "DEPLOY_DRIVE"
    Verify-Env "CI_PROJECT_NAME"

    # C:\products or D:\products *most* of the time.
    $root = "$env:DEPLOY_DRIVE\products"
    $destination = "$root\$env:CI_PROJECT_NAME"
    $backup_loc = "$root\backup"

    # Removes prior binaries
    Backup-Binary -source $root -name $env:CI_PROJECT_NAME -dest $backup_loc

    # Copy binary locally since we're deploying to local machine.
    Copy-Item -Recurse -Force -Path $folder_to_copy -Destination $destination -ErrorAction Stop

    # Run the init script the developer has written
    Invoke-Expression "$init_file" -ErrorAction Stop

}

function Deploy-Remote {

    $session = New-PSSession -ComputerName $hostname

    $DEPLOY_DRIVE = Invoke-Command -Session $session -ScriptBlock { 
        [Environment]::GetEnvironmentVariable("DEPLOY_DRIVE")
    } -ErrorAction Stop

    $root = "$DEPLOY_DRIVE\products"
    $destination = "$root\$env:CI_PROJECT_NAME"
    $backup_loc = "$root\backup"

    Write-Host "$root = root $destination = destination $backup_loc = backup_location"

    Invoke-Command -Session $session -ScriptBlock ${function:Backup-Binary} -ArgumentList $root,$env:CI_PROJECT_NAME,$backup_loc -ErrorAction Stop

    Copy-Item -Recurse -Force -ToSession $session -Path $folder_to_copy -Destination $destination -ErrorAction Stop

    Invoke-Command -Session $session -FilePath $init_file -ErrorAction Stop

    Remove-PSSession $session -ErrorAction Stop

}

if ( $hostname.ToLower() -eq $env:COMPUTERNAME.ToLower() ) {

    Deploy-Local

} else {

    Deploy-Remote

}
斯克兰博

这个答案由@ mklement0从提供的链接中给出(我在github上开始的一个问题)

@huffstler:

是的,但是与#2934相同,只是在一个更大的命令中:

  • 当为subdir时。a正在被复制,$ b还不存在,因此a的内容被直接复制到$ b中(上述行为(a))。
  • 通过时间子目录。复制b时,$ b已经存在,那就是出现不一致的时候:b的内容复制到$ b / b(上面的行为(b))。

因此,如果再次运行该命令,则可以实现所需的行为。

鉴于当前的行为,您可以按照以下方法解决此问题:

Get-ChildItem -Path $a |
ForEach-Object { New-Item -Force -Type Directory $b } { 
  Copy-Item -Recurse -Path $_.FullName -Destination $b
}

但是,更大的问题是,应该针对行为(a)还是行为(b)解决这种矛盾。

您明确预期(a),但其他人根据xcopy可能会有不同的期望。

坦白说,我困惑于发现与Unix世界中的Copy-Item -Recurse(cp -R)相同的不一致之处。

当前获得可预测行为的唯一方法是:

  • 确保目标目录。已经存在。

  • 然后,根据您是要行为(a)还是(b):

  • 要获得行为(a):明确指定源目录的内容:

    Copy-Item -Recurse -Force $a/* $b

    • 请注意需要使用-Force,以确保也复制了隐藏项。

    • 在Unix上使用cp,您可以更简单地$a/.做到这一点,但这在PowerShell中不起作用。

  • 获得行为(b):无需采取进一步措施。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

PowerShell使用xcopy,robocopy或copy-item

Powershell Copy-Item 退出代码 1

PowerShell Copy-Item不复制所有文件

如何在PowerShell中使用Copy-Item覆盖文件

如何修复“value null Copy-Item Powershell”错误

Powershell Copy-Item -recurse不会选择新目录

Powershell Copy-Item 不去目的地

PowerShell Copy-Item在八达通中给出错误

如何在Powershell中的Copy-Item cmdlet的文件路径中包含变量

Powershell:Get-ChildItem-传递给Rename-Item和Copy-Item的管道

复制到网络共享不适用于 powershell Copy-Item

即使文件夹存在,Powershell Copy-Item 也不复制

Powershell-Invoke-Command脚本块中的“ Copy-item”命令

如何在非高架Powershell中运行copy-item(以管理员身份)?

Copy-Item 不包括 PowerShell 中源目录的子文件夹文件

Powershell Copy-Item复制无法复制到叶子上的UNC子目录的内容

使用copy-item命令时Powershell不排除特定的子文件夹

为什么Powershell和python对于同一命令给出不同的结果?

image_tag对于相同的路径给出不同的结果

需要在Powershell中创建动态文件夹并将其用作copy-item中的变量

为什么xgboost树的相同路径给出2个不同的预测?

“ copy con”或“ type con>”在Powershell中是否等效?

Bash 相当于来自 powershell 的“copy /b”

在Powershell中,OpenSSH是否与ssh-copy-id等效?

使用PowerShell Copy合并3个部分文件

Powershell ps1 Get Children Copy 命令基本

Azure devops powershell 在同一查询上给出的结果与本地 powershell 不同

我在Powershell中使用Copy-item命令时看到在目标文件夹中与文件一起创建的空源目录

与Powershell 3.0中相同命令的结果不同