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

7 投票
4 回答
12331 浏览
提问于 2025-04-17 23:30

我刚写了一个简单的Python脚本,用来移动一些大文件夹(都在同一个硬盘上),我错误地以为Windows的命令行工具不会那么糟糕,像在Windows资源管理器中那样,使用move Root\Dir1 Root\Dir2命令可以合并文件夹里的内容。其实我并不在乎文件夹里有没有重复的文件,因为根本就没有。

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

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 ???

看来唯一的办法就是先复制再删除。真是让人感到无奈。

相关内容:

我可不想写代码一个个复制文件。有没有什么办法可以在不复制的情况下移动文件夹并替换内容?

如果可以的话,我更希望使用一些本地的可执行文件。如果支持的话,我也很乐意用Python来实现。

4 个回答

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"
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

这里的 :strip 调用是从 https://stackoverflow.com/a/11925464/13900705 这个链接中获取的,并进行了修改,以支持包含空格的路径。

1

合并并覆盖

这个修改过的功能会把目标文件夹中与源文件夹中同名的文件覆盖掉。也就是说,如果目标文件夹里有和源文件夹里同名的文件,目标文件夹里的文件会被替换掉。那些在目标文件夹中没有重复的文件则不会受到影响。同时,源文件夹中不存在的文件和文件夹会被从源文件夹复制到目标文件夹。这个功能是基于@jozxyqk的代码改编的。

def merge_overwrite_Tree(sourceRoot, destRoot):
  #https://stackoverflow.com/questions/22588225/how-do-you-merge-two-directories-or-move-with-replace-from-the-windows-command
  '''
  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
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

如果以后有合适的答案,请务必分享出来!

撰写回答