如何在Windows命令行中合并两个目录或移动并替换而不是复制?

7

我刚刚写了一个快速的Python脚本来移动一些大目录(都在同一驱动器上),错误地假设Windows命令行工具不是完全的玩笑,并且move Root\Dir1 Root\Dir2会像Windows资源管理器GUI一样合并内容。我真的不在意它是否替换或跳过文件夹中的重复文件,因为没有任何重复的。

不幸的是(在管理员命令提示符中),

C:\>mkdir a

C:\>mkdir b

C:\>mkdir b\a

C:\>move b\a .
Overwrite C:\a? (Yes/No/All): yes
Access is denied.

... :O

... ?? really ??!?

... no, actually really really ???
似乎唯一的方法是复制然后删除。非常痛苦可悲。 相关内容: - 如何将一个目录树的内容移动到另一个目录中? - 如何通过批处理命令合并两个文件夹? - 如何修复在Windows 7中使用move命令时出现“拒绝访问”的问题? 我不想逐个编写复制文件的代码。有没有办法在不复制的情况下实现替换文件夹的移动? 如果可能,我更喜欢使用一些本地可执行文件。如果Python支持它,我也会很高兴使用它。

看一下 robocopy:http://technet.microsoft.com/en-us/library/cc733145.aspx。这里它被用来解决类似(我认为)你的问题:http://superuser.com/questions/606710/merge-directories-without-overwriting-conflicts。 - wmz
@wmz 谢谢,我会再看一下它,尽管我认为它仍然执行的是同一文件系统上的复制/删除而不是移动操作。 - jozxyqk
4个回答

8

手动移动所有文件的Python解决方案。我仍然感到愚蠢。

def moveTree(sourceRoot, destRoot):
    if not os.path.exists(destRoot):
        return False
    ok = True
    for path, dirs, files in os.walk(sourceRoot):
        relPath = os.path.relpath(path, sourceRoot)
        destPath = os.path.join(destRoot, relPath)
        if not os.path.exists(destPath):
            os.makedirs(destPath)
        for file in files:
            destFile = os.path.join(destPath, file)
            if os.path.isfile(destFile):
                print "Skipping existing file: " + os.path.join(relPath, file)
                ok = False
                continue
            srcFile = os.path.join(path, file)
            #print "rename", srcFile, destFile
            os.rename(srcFile, destFile)
    for path, dirs, files in os.walk(sourceRoot, False):
        if len(files) == 0 and len(dirs) == 0:
            os.rmdir(path)
    return ok

如果有合适的答案,请发表一篇恰当的回复!


1
也许我会尝试从底部向上进行单次遍历,并立即删除路径像这样。感谢提供代码。 - Ciro Santilli OurBigBook.com
@CiroSantilli新疆改造中心996ICU六四事件,我已经在你的实现中添加了jozxyqk的检查
if os.path.isfile(destFile): continue 并且使用shutil删除目录及其所有未移动(由于已存在)的文件 shutil.rmtree(os.path.join(path, dirname))```
- Octav

1

如果你只想使用批处理,那么你唯一的选择是使用move

正如你已经指出的那样,move能够覆盖文件,但不能合并文件夹。因此,为了解决这个问题,下面的脚本逐个移动文件。为了确定文件相对于目标的位置,源文件夹被从绝对文件路径中剥离。

通过运行call:move "C:\path\source" "C:\path\dest"可以将一个文件夹(包括合并)移动到另一个文件夹中。

请注意,该脚本需要禁用延迟扩展。

:: Strip one path from another
::
:: %~1 relative path
:: %~2 absolute path
:strip
set "rec_a_part="
set "rec_a="
set "rec_r_part="
set "rec_r="
for /f "tokens=1,* delims=\" %%t in ("%~2") do (
  set "rec_a_part=%%t"
  set "rec_a=%%u"
)
for /f "tokens=1,* delims=\" %%t in ("%~1") do ( 
  set "rec_r_part=%%t"
  set "rec_r=%%u"
)
if not "!%newp%!"=="!!" set "newp=%newp%\"
if not "!%rec_a_part%!"=="!%rec_r_part%!" set "newp=%newp%%rec_r_part%"
if not "!%rec_r%!"=="!!" call:strip "%rec_r%" "%rec_a%"
goto:eof

:: Internal call handing the move command
::
:: %~1 source dir relative path
:: %~2 source dir absolute path
:: %~3 dest dir
:execute_move
set "newp="
call:strip "%~1" "%~2"
mkdir "%~3\%newp%\.." 2>nul
move /y "%~1" "%~3\%newp%" >nul
goto:eof

:: Moves all files from one folder into another overwriting any existing files
::
:: %~1 source dir
:: %~2 dest dir
:move
for /r "%~1" %%i in (*) do (
  call:execute_move "%%i" "%~1" "%~2"
)
rd /s /q "%~1"
goto:eof
< p > :strip 呼叫是从 https://stackoverflow.com/a/11925464/13900705 中获取的,并进行了修复以支持具有空格的路径。


1

覆盖合并

此修改过的函数会覆盖目标文件夹中与源文件夹同名的文件。已存在但不重复的文件将不受影响。不存在的文件和文件夹将从源文件夹复制到目标文件夹。此函数基于@jozxyqk的代码。

def merge_overwrite_Tree(sourceRoot, destRoot):
  #https://dev59.com/Fn3aa4cB1Zd3GeqPjer5
  '''
  Updates destenation root, overwrites existing files.
  :param sourceRoot: Root folder from wehere to copy the files
  :param destRoot: Destination folder where new folders and files are created and new files are added
  :return: !=0 in case of errors
  '''
  if not os.path.exists(destRoot):
    return 1
  ok = 0
  for path, dirs, files in os.walk(sourceRoot):
    relPath = os.path.relpath(path, sourceRoot)
    destPath = os.path.join(destRoot, relPath)
    if not os.path.exists(destPath):
      print("create: %s"%destPath)
      os.makedirs(destPath)
    for file in files:
      destFile = os.path.join(destPath, file)
      if os.path.isfile(destFile):
        print "\n...Will overwrite existing file: " + os.path.join(relPath, file)
        #ok = False
        #continue
      srcFile = os.path.join(path, file)
      # print "rename", srcFile, destFile
      # os.rename(srcFile, destFile) # performs move
      print("copy %s to %s"%(srcFile, destFile))
      shutil.copy(srcFile, destFile) # performs copy&overwrite
  return ok

0

看看这个对你是否有效。

@echo off'
md "c:\a"
md "c:\b"
type nul > "c:\a\file1.txt"
type nul > "c:\a\file2.txt"
move "c:\a\*.*" "c:\b"

使用move*命令时,我收到了“文件名、目录名或卷标语法不正确”的错误消息。同时,当两个子文件夹具有相同的名称时,我认为也会出现相同的问题。 - jozxyqk
那段代码在这里可以运行,即使第一行有个拼写错误。也许你的路径中有一个第三方的move命令。 - foxidrive

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