Я предлагаю следующий код, производящий в точности нужный исходный вывод в файле журнала:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "LOGFILE=MyLogFile.log"
del "%LOGFILE%" 2>nul
call :Logit >>"%LOGFILE%"
endlocal
exit /B 0
:Logit
set "FileDate=%DATE:~-4%%DATE:~-10,2%%DATE:~-7,2%_%TIME:~0,2%%TIME:~3,2%%TIME:~6,2%"
for /F "tokens=1* delims=:" %%I in ('%SystemRoot%\System32\xcopy.exe "I:\DF\AB\Data.xlsx" "D:\TL\BACKUP\Data_%FileDate%.xlsx*" /C /V /Y 2^>nul') do (
if not "%%J" == "" (
echo %%I:%%J
) else (
echo %FileDate% : %%I
)
)
goto :EOF
Дата и время, зависящие от региона, переформатируются в YYYYMMDD_HHmmss
с использованием строковых подстановок динамических переменных среды DATE
и TIME
, как подробно описано, например, при ответе на Что означает% date: ~ - 4,4 %% дата: ~ -10,2 %% дата: ~ -7,2% _% время: ~ 0,2 %% время: ~ 3,2% значит? Для гораздо медленнее, но Решение, не зависящее от региона, для получения даты / времени в определенном формате, см., например, ответ на % date% дает другой результат в пакетном файле при запуске из запланированных задач на сервере 2016 .
Текущие дата и время в формате YYYYMMDD_HHmmss
назначены переменной среды FileDate
, используемой дважды в следующей строке, один раз в имени целевого файла и еще раз в выводе последней строки переформатированного вывода команды XCOPY .
Используемая здесь командная строка XCOPY , например:
C:\Windows\System32\xcopy.exe "I:\DF\AB\Data.xlsx" "D:\TL\BACKUP\Data_20180831_163959.xlsx*" /C /R /V /Y 2>nul
Эта командная строка выполняется FOR в отдельном командном процессе, запускаемом FOR с cmd.exe /C
в фоновом режиме. FOR захватывает все строки, записанные для обработки STDOUT этого командного процесса перед обработкой захваченных строк.
XCOPY выводит для обработки STDOUT имена скопированных файлов с полным путем и в качестве последней строки сводную информацию. Ошибки при копировании файлов записываются в обработчик STDERR , которые подавляются путем перенаправления их на устройство NUL .
Прочтите также статью Microsoft о Использование операторов перенаправления команд для объяснения 2>nul
. Оператор перенаправления >
должен быть экранирован с помощью символа вставки ^
в командной строке FOR , чтобы интерпретироваться как литеральный символ, когда интерпретатор команд Windows обрабатывает эту командную строку перед выполнением команды FOR , которая выполняет встроенную командную строку xcopy
в отдельном командном процессе, запущенном в фоновом режиме.
Звездочка *
в конце имени целевого файла должна быть в двойных кавычках строки второго аргумента, а не снаружи, потому что в противном случае cmd.exe
соответственно xcopy.exe
должен исправить этот неправильный синтаксис.
Обратите внимание, что уловка с *
в конце имени целевого файла работает здесь случайно, поскольку исходный и целевой файлы имеют одинаковое расширение, а имя исходного файла всегда короче, чем имя целевого файла. В противном случае команда не выполнится или целевой файл получит нежелательное имя, представляющее собой конкатенацию имени целевого файла + символы имени исходного файла после n символов имени целевого файла.
В целом, существуют более эффективные методы, позволяющие избежать остановки при запросе, который XCOPY запросов в случае копирования одного файла с новым именем файла. Письмо для ответа на приглашение может быть сначала выведено на STDOUT , перенаправленное на обработку STDIN из XCOPY , как продемонстрировано, независимо от языка ответа в запросах пакетного файла для файла или папки .
Захваченный вывод XCOPY обрабатывается FOR построчно с пропуском пустых строк и строк, начинающихся с точки с запятой ;
в качестве символа конца строки по умолчанию для параметра eol=
здесь не используется.
Цель здесь - вывести все строки с полным квалифицированным файлом, выведенным с помощью XCOPY в фоновом командном процессе, также в этом командном процессе, но вывести последнюю строку со сводной информацией, отличной, предварительно ожидая ее с датой / временем в требуемом формате, пробел, двоеточие и еще один пробел.
По этой причине поведение разделения строк по умолчанию на пробелах / табуляциях с назначением только первой подстроки (токена) указанной переменной цикла I
изменяется здесь параметрами tokens=1* delims=:
. FOR теперь разделяет строку на двоеточия.
Только строки с полным именем файла, начинающиеся с буквы диска и двоеточия, вообще содержат двоеточие. В таких строках буква диска назначается указанной переменной цикла I
, как указано tokens=1
. Остальная часть строки имени файла после первого двоеточия присваивается без дальнейшего разделения на следующую переменную цикла в соответствии с ASCII-таблицей для переменной цикла J
, которая находится здесь после двоеточия после буквы диска.
Строка сводной информации не содержит двоеточия. По этой причине FOR присваивает всю сводную информацию переменной цикла I
, а J
содержит пустую строку.
Переменная цикла J
никогда не бывает пустой в строке с именем файла, начинающимся с буквы диска и двоеточия. Этот факт используется здесь, чтобы определить, следует ли выводить строку из XCOPY как есть, вставляя удаленное двоеточие между буквой диска и путем к файлу + имя файла + расширение файла или выводя сводную информацию с указанием даты / времени в начало.
Обратите внимание, что этот метод работает только при копировании файлов с диска с буквой диска. Для исходных файлов с UNC путем потребуется другой метод.
На самом деле копирование одного файла можно сделать намного проще с помощью команды COPY вместо XCOPY даже с / на сетевой диск или когда имя исходного / целевого файла указывается с помощью UNC путь. COPY также имеет опции /V
и /Y
и даже /Z
, как XCOPY . COPY не создает целевую структуру каталогов, такую как XCOPY , но это можно сделать с помощью команды MD ранее. COPY не может перезаписать файл только для чтения, так как XCOPY может использоваться при использовании опции /R
, но это ограничение COPY , скорее всего, здесь не имеет значения , И COPY не копирует файл со скрытым набором атрибутов. Тем не менее, как правило, лучше всего копировать один файл с помощью команды COPY вместо XCOPY .
Итак, вот еще одно решение с использованием команды COPY , которая работает быстрее, чем решение XCOPY , так как нет причины выполнять копирование файла в отдельном командном процессе, захватывать любые разделить их и вывести их снова соединенными или измененными.
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "LOGFILE=MyLogFile.log"
md "D:\TL\BACKUP" 2>nul
del "%LOGFILE%" 2>nul
call :Logit >>"%LOGFILE%"
endlocal
exit /B 0
:Logit
set "FileDate=%DATE:~-4%%DATE:~-10,2%%DATE:~-7,2%_%TIME:~0,2%%TIME:~3,2%%TIME:~6,2%"
echo I:\DF\AB\Data.xlsx
copy /B /V /Y "I:\DF\AB\Data.xlsx" "D:\TL\BACKUP\Data_%FileDate%.xlsx" >nul 2>nul && echo %FileDate% : 1 File(s) copied|| echo %FileDate% : 0 File(s) copied
goto :EOF
Это решение также имеет то преимущество, что линейный вывод в случае успеха или ошибки может быть полностью настроен. COPY завершается со значением, большим 0 при ошибке, например, исходный файл недоступен или целевой файл / каталог защищен от записи в настоящее время или на постоянной основе.
Пример лучшего вывода для одного скопированного файла в случае успеха или ошибки (только подпрограмма):
:Logit
set "FileDate=%DATE:~-4%%DATE:~-10,2%%DATE:~-7,2%_%TIME:~0,2%%TIME:~3,2%%TIME:~6,2%"
copy /B /V /Y "I:\DF\AB\Data.xlsx" "D:\TL\BACKUP\Data_%FileDate%.xlsx" >nul 2>nul
if not errorlevel 1 (
echo %FileDate% : Copied successfully I:\DF\AB\Data.xlsx
) else (
echo %FileDate% : Failed to copy file I:\DF\AB\Data.xlsx
)
goto :EOF
Конечно, также можно использовать командную строку
set "FileDate=%DATE:/=%_%TIME::=%"
в командном файле, чтобы получить дату и время в формате MMDDYYYY_HHmmss.ms
, если это действительно требуется сейчас. Я не рекомендую этот формат даты / времени, так как он не подходит для алфавитного списка всех файлов Data_*.xlsx
в каталоге D:\TL\BACKUP
. Список файлов, отсортированных по имени, имеет формат даты / времени YYYYMMDD_HHmmss
, автоматически также отсортированный по дате / времени.
Чтобы понять используемые команды и то, как они работают, откройте окно командной строки, выполните там следующие команды и полностью прочитайте все страницы справки, отображаемые для каждой команды.
call /?
copy /?
del /?
echo /?
endlocal /?
exit /?
for /?
goto /?
if /?
md /?
set /?
setlocal /?
xcopy /?
Смотри также: