PDA

Показать полную графическую версию : Перенос каталогов и файлов


RealDT
19-12-2018, 19:48
Добрый день.

Друзья, необходимо выборочно перенести каталоги (и подкаталоги) и файлы в резервную папку.
Список выбранных каталогов сохранён в файле dir.txt, например:
Docs\!Каталог 1
Docs\Каталог 2
Docs\Каталог 3

Для выборочного переноса выполняется следующий код:
@echo off
cls
setlocal enabledelayedexpansion
set curdisk=%~d0

for /f "usebackq delims=" %%A in ("dir.txt") do (
Set "folder_from="%curdisk%\%%A""
set "folder_where="%curdisk%\%date:~6,4%-%date:~3,2%-%date:~0,2% reserv\%%A""

if not exist !folder_where! md !folder_where!

move /Y !folder_from!\*.* !folder_where!
FOR /F "delims=" %%I IN ('DIR /B /AD !folder_from!') DO (
move /Y !folder_from!\"%%I" %1 !folder_where!
)
if exist !folder_from! rd !folder_from! | echo !folder_from!
)

Но если в названии выбранного каталога или в названии его подкаталогов имеется "!" (восклицательный знак), код не работает. Из названия каталогов/подкаталогов исчезает "!".

Если в файле dir.txt знак ! экранировать ^, код работает только с этим каталогом.
Docs\^!Каталог 1

Структура этого каталога может быть такой:
Docs\!Каталог 1
Docs\!Каталог 1\Папка 1!
Docs\!Каталог 1\!Папка 2
Docs\!Каталог 1\Папка !3
Docs\!Каталог 1\Папка 4
Т.е. ! знак может оказаться в любом месте в названии подкаталога и/или файлов.
Каким образом экранировать ! знак в подкаталогах и файлах этой папки? Может у кого есть другое решение по переносу заданных списком каталогов со всеми файлами?

Iska
19-12-2018, 21:45
Может у кого есть другое решение по переносу заданных списком каталогов со всеми файлами? »
Есть несколько вариантов. Например, не использовать отложенное раскрытие переменных окружения. Перейти на WSH/PoSH.

Зачем Вы используете здесь:
if exist !folder_from! rd !folder_from! | echo !folder_from!
конвеер?!

megaloman
19-12-2018, 22:51
RealDT, не использовать отложенное раскрытие переменных окружения »Попытался переделать Ваш код, не знаю, что получилось (корежить чужой код - нудное неблагодарное занятие), но васклицательного знака мой код не боится.@Echo Off
cls
Set "curdisk=%~d0"
For /f "usebackq delims=" %%A in ("dir.txt") Do (
RoboCopy "%curdisk%\%%A" "%curdisk%\%date:~6,4%-%date:~3,2%-%date:~0,2% reserv\%%~nxA" "*.*" /S /IS /Move
)
PauseДо меня совершенно не доходит строка:move /Y !folder_from!\"%%I" %1 !folder_where! »Если моё извращение Вашего кода Вас не устраивает, объясните подробнее, что Вам надо.

RealDT
21-12-2018, 12:36
Спасибо за отклики.
По порядку:

Перейти на WSH/PoSH »
мне такое пока не ведомо, посмотрю. если есть ссылки, просьба черкануть...

это
if exist !folder_from! rd !folder_from! | echo !folder_from!
нужно чтобы удалить выборочную папку (которая указана в dir.txt) c диска после переноса.

эта команда
move /Y !folder_from!\"%%I" %1 !folder_where!
переносит и каталоги и файлы. %1 - лишнее, можно не указывать

Если моё извращение Вашего кода Вас не устраивает, объясните подробнее, что Вам надо.
Предложенный Вами код работает. Но, если move переносит файлы, то robocopy их копирует. Команда move (а не copy & rd или robocopy) на физическом уровне работает в разы быстрее, поскольку работает только в секторах HDD, где размещены ссылки на содержание файлов, а не данные этих файлов. Другими словами - copy/robocopy резервирует и создаёт на диске новый блок данных, а move - только меняет ссылки на расположение этих данных. Скорость работы move и copy/robocopy хорошо видна на больших файлах и незаметна если файлов много, но они небольшого размера.

Вот код, который переносит (не копирует) один заданный каталог и обрабатывает также каталоги/файлы с восклицательными знаками:
set curdisk=%~d0
Set dir1=Docs\!КОНТАКТЫ
Set folder_from=%curdisk%\%dir1%
Set folder_where=%curdisk%\%date:~6,4%-%date:~3,2%-%date:~0,2% reserv\%dir1%
if not exist "%folder_where%" md "%folder_where%"
if exist "%folder_from%\*.*" move /Y "%folder_from%\*.*" "%folder_where%"
FOR /F "delims=" %%I IN ('DIR /B /AD "%folder_from%"') DO (move /Y "%folder_from%\%%I" %1 "%folder_where%")
if exist %folder_from% rd %folder_from%

Пока не разобрался, как в переменную dir1 в цикле вносить новое значение из файла dir.txt со списком выбранных каталогов.

объясните подробнее, что Вам надо.
Изначально решалось это:
Перенести избранные каталоги с их содержанием (подкаталоги и файлы) в резервную папку на текущем диске. Название диска не известно.

megaloman
21-12-2018, 13:18
RealDT, Но, если move переносит файлы, то robocopy их копирует. Как говорил мой начальник, не надо ля-ля. :) Robocopy c ключом /mov переносит файлы с путями, а /move и директори, но при этом они будут удалены из источника, если только пустые. Я проверял, работает.
Проделайте robocopy /? >c:\robocopy.txt и читайте описание команды в файле c:\robocopy.txt
У меня ощущение, что Вы не проанализировали результат выполнения моего кода. Либо не точно его повторили, без всех ключей. Он полностью решает поставленную задачу, в том числе и чтение папок из списка в файле

RealDT
21-12-2018, 14:53
Код проверял в двух вариантах:
- на небольших файлах, которых много (код отлично справился за неск секунд) и
- на файлах > 1.5 ГБ - robocopy их начинает копировать, на экране светится прогресс копирования, после некоторого ожидания на середине одного из файлов - прервал работу кода...

megaloman
21-12-2018, 18:03
RealDT, у меня нет большого опыта с RoboCopy, озвученные проблемы мне кажутся странными. @Echo Off
cls
Set "Disk=%~d0"
Set "List=%Disk%\dir.txt"
Set "Backup=%Disk%\%Date:~6,4%-%Date:~3,2%-%Date:~0,2% reserv"

For /f "usebackq delims=" %%D in ("%List%") Do (
For /F "usebackq delims=" %%F In (`Dir "%Disk%\%%D\" /B /S /A:D 2^>nul^|Sort /R`) Do (
Call :MyMove "%%~dpD" "%Backup%\" "%%F"
)
Call :MyMove "%%~dpD" "%Backup%\" "%Disk%\%%D"
)
pause
GoTo :Eof

:MyMove
If Not Exist %3 Exit /B 1
Set "Out=%~3"
Call Set "Out=%%Out:%~1=%~2%%"
If Not Exist "%Out%" Md "%Out%"
2>nul Move /Y "%~3\*.*" "%Out%\"
Rd %3
GoTo :Eof

RealDT
27-12-2018, 12:44
Спасибо за варианты решения.
Вот ещё один вариант решения:

@echo off
set curdisk=%~d0

Set folder_where=%curdisk%\%date:~6,4%-%date:~3,2%-%date:~0,2% reserv

if not exist "%folder_where%" md "%folder_where%"

FOR /F "tokens=1,2* delims=;" %%I IN (dir.txt) DO (
if not exist "%folder_where%\%%J" md "%folder_where%\%%J"
move /Y "%curdisk%\%%I" "%folder_where%\%%J"
)

При этом структура файла dir.txt поменялась и должна быть такой:
Каталог1\!Папка11\!Папка111\Папка1111;Каталог1\!Папка11\!Папка111
Каталог1\!Папка12\!Папка121\Папка1121;Каталог1\!Папка12\!Папка121
Каталог2\Папка12\Папка!331;Каталог2\Папка12
Каталог3\Папка13\;Каталог3

Т.е.:
- в переменную %%I записывается каталог "что переносить";
- в переменную %%J записывается часть каталога "куда переносить", полный путь "куда переносить" будет таким %folder_where%\%%J

Отличия от начального варианта решения:
- убрал SETLOCAL enabledelayedexpansion, который удалял воскличательные знаки в именах каталогов и файлах;
- убрал внешний цикл FOR (оставил только один цикл);
- добавил неявную переменную %%J
- изменил структуру dir.txt, в котором каждая строка формирует значения для %%I и %%J.

Iska
27-12-2018, 17:04
RealDT, только имейте в виду, что curdisk — не текущий диск, а диск, на котором находится пакетный файл.




© OSzone.net 2001-2012