4

У меня есть два каталога, так что каталог B является, по крайней мере, полным зеркалом A Например:

A/
    directory1/
        file1
    directory2/
        file2
    file3
B/
    directory1/
        file1
    directory2/
        file2
    directory3/
        file4
    file3
    file5

Обратите внимание, что B содержит все файлы, присутствующие в A , а также потенциально другие файлы.

Что мне нужно, это удалить все файлы и каталоги из B которые не существуют в A В приведенном выше примере directory3 , file4 и file5 будут удалены, так что после операции B снова будет полное зеркало A без других файлов:

B/
    directory1/
        file1
    directory2/
        file2
    file3

Для Windows XP.

2 ответа2

5

Это не невозможно сделать с помощью пакетного скрипта. Однако самый простой способ - использовать RoboCopy . К сожалению, это включено только в Vista и более поздних версиях, но пользователи XP могут установить этот набор ресурсов или получить автономную копию в другом месте.

robocopy <source> <destination> /mir

Из справки (robocopy /?):

/E :: copy subdirectories, including Empty ones.
/PURGE :: delete dest files/dirs that no longer exist in source.
/MIR :: MIRror a directory tree (equivalent to /E plus /PURGE).

К сожалению, если вы не можете запустить внешние исполняемые файлы, потребуется пакетный скрипт.

Редактировать:

В целях полноты я написал этот пакетный скрипт. Просто обязательно проверь в безопасном месте кулак, хотя, похоже, сработает. Возможно, вы захотите удалить (или прокомментировать, передвинуть rem перед) строки del и rmdir для тестирования.

@echo off

setlocal EnableDelayedExpansion

set dirsrc=%~f1
set dirdest=%~f2

echo Source: "%dirsrc%"
echo Destination: "%dirdest%"

echo.
echo.
echo Cleaning files...

for /f "tokens=*" %%a in ('dir /s /b /a:-d "%dirdest%"') do (
    set curdest=%%a
    set cursrc=!curdest:%dirdest%=%dirsrc%!

    if not exist !cursrc! (
        echo Deleting "!curdest!"
        del "!curdest!"
    )
)

echo.
echo.
echo Cleaning directories...

set NLM=^


set NL=^^^%NLM%%NLM%^%NLM%%NLM%
rem Two lines left empty for NewLine to work

for /f "tokens=*" %%a in ('dir /s /b /a:d "%dirdest%"') do (
    set curdest=%%a
    set cursrc=!curdest:%dirdest%=%dirsrc%!

    if not exist !cursrc! (
        set rmlist=!curdest!?!rmlist!
    )
)

set rmlist=!rmlist:?=%NL%!

for /f "tokens=*" %%a in ("!rmlist!") do (
    if exist %%a (
        echo Removing directory "%%a"
        rmdir "%%a"
    )
)

endlocal

Использование довольно просто: сохраните как файл .bat (например, purge.bat) и назовите его так: purge source destination . Если у вас есть пробелы в исходных или целевых путях, вам придется добавлять кавычки, как и в любой другой командной строке ... команда.

Я кратко объясню.

Во-первых, файлы удаляются. Он выполняет замену строки, заменяя путь назначения на путь источника, поэтому он может проверить, существует ли файл в источнике. Это позволяет мне сообщать, какие файлы удаляются, и когда я приступаю к удалению каталогов, они гарантированно не содержат файлов. Это позволяет мне избежать уродства rmdir /s , который удаляет все подкаталоги и файлы, так же как и rm -r в Linux. Кроме того, различие между файлом и каталогом только по пути в пакете является довольно запутанным.

Когда я удаляю каталоги, я строю строку в обратном порядке, содержащую все пути к каталогам. Это так, что самый глубокий уровень удаляется первым, потому что dir /s всегда обеспечивает самые глубокие уровни последними. Это, однако, вероятно, будет в обратном алфавитном порядке.

Кроме того, спасибо за сценарий bash Eroen, но я не могу читать bash;)

0

Я не большой сценарист для пакетной оболочки Windows, но в bash работает следующее. Затем вы можете установить Cygwin и запустить его. Если кто-то с большим опытом работы со сценариями Windows хочет перенести его на пакетный синтаксис, идите прямо сейчас и украдите этот ответ.

Кроме того, мог бы быть лучший способ сделать это, я сделал это главным образом потому, что это был интересный вызов, а не потому, что я нуждался и решил это раньше.

Настроить

$ ls -R
.:
a  b

./a:
i  j  k

./b:
i  j  k  l
$ cd b/

Решение

$ for i in *
> do
> [[ -e "../a/$i" ]] || echo rm -r "${i}"
> done
rm l

Если вы удалите команду echo команда rm будет выполнена (и удалит файлы) вместо только что напечатанной. Этот способ просто лучше для проверки.

В моем простом "мокром" тесте он хорошо работал с именами файлов, содержащими пробелы.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .