Как скопировать два последних файла журнала в другую папку? - PullRequest
1 голос
/ 28 июня 2019

Я пытаюсь скопировать два последних журнала ошибок из исходного местоположения в другую папку, к которой проще получить доступ.Я нашел код ниже в сообщении Магу здесь, и инструкции должны были заменить echo %%i соответствующей командой копирования.По какой-то причине мне тяжело с этим.

@ECHO OFF
SETLOCAL
SET transfer=xx
FOR /f "delims=" %%i IN ('dir/b/a-d/o-d *.*') DO IF DEFINED transfer CALL SET transfer=%%transfer:~1%%&ECHO %%i

Моя последняя строка с заменой echo %%i выглядит так:

SET transfer=%%transfer:~1%%& xcopy /y "C:\source_location" "D:\target_location"

1 Ответ

1 голос
/ 29 июня 2019

Этот пакетный файл можно использовать для задачи копирования только двух самых новых файлов в указанном исходном каталоге в указанный целевой каталог, независимо от того, какой каталог является текущим каталогом при выполнении пакетного файла.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FileCount=xx"
set "SourcePath=C:\source_location"
set "TargetPath=D:\target_location"

set "SourcePath=%SourcePath:/=\%"
set "TargetPath=%TargetPath:/=\%"

if not "%SourcePath:~-1%" == "\" set "SourcePath=%SourcePath%\"
if not "%TargetPath:~-1%" == "\" set "TargetPath=%TargetPath%\"

for /F "eol=| delims=" %%I in ('dir "%SourcePath%" /A-D /B /O-D 2^>nul') do (
    %SystemRoot%\System32\xcopy.exe "%SourcePath%%%I" "%TargetPath%" /C /I /Q /H /R /Y >nul
    call set "FileCount=%%FileCount:~1%%"
    if not defined FileCount goto FileCopyDone
)

:FileCopyDone
rem Other commands can be inserted here.
endlocal

Пакетный файл сначала устанавливает локальную среду с включенными расширениями команд, если это необходимо здесь, и с отключенным отложенным расширением переменной среды, чтобы иметь возможность копировать также файлы, в которых полное квалифицированное имя файла (диск + путь + имя + расширение) содержит один илибольше восклицательных знаков.Пожалуйста, прочитайте этот ответ для получения подробной информации о командах SETLOCAL и ENDLOCAL и что происходит в фоновом режиме при использовании этих двух команд.

Количествоколичество копируемых файлов определяется количеством x символов строки, присвоенной переменной среды FileCount.xx означает копирование двух файлов, а xxxx - копирование четырех файлов.В действительности не имеет значения, какой символ используется в строке, присвоенной переменной среды FileCount, длина строки имеет значение, которое должно быть не менее одного символа.

Тогда пакетный файл удостоверяется, что \используется в исходном и целевом путях, потому что это разделитель каталогов в Windows, а не /, как в Linux и Mac.

Следующий исходный и целевой путь определены в пакетном файле.Эти две переменные среды также могут быть определены динамически, а не исправлены путем назначения первого и второго аргумента, передаваемого пакетному файлу этим двум переменным среды.

Пакетный файл записывается для исходного пути, всегда заканчивающегося каталогом Windowsразделитель \ и по этой причине пакетный файл гарантирует, что последний символ исходного пути действительно является обратной косой чертой.

Целевой путь должен заканчиваться обратной косой чертой.Это очень важно при использовании в качестве целевой строки для команды XCOPY , как очень подробно объяснено в моем ответе на командный файл запрашивает файл или папку .По этой причине пакетный файл гарантирует, что целевой путь также заканчивается обратной косой чертой.

Команда FOR с параметром /F запускает новый командный процесс с %ComSpec% /c и командной строкойуказано между ' как дополнительные аргументы в фоновом режиме.Таким образом, выполнение FOR осуществляется с использованием обычного пути установки Windows:

C:\Windows\System32\cmd.exe /c dir "C:\source_location\" /A-D /B /O-D 2>nul

DIR , выполняемого при фоновом поиске команды с указанными аргументами

  • в указанном исходном каталоге
  • для файлов из-за опции /A-D (атрибут не каталог)
  • , соответствующий шаблону подстановочных знаков по умолчанию * (все)

и выводит

  • в голом формате из-за опции /B только имена файлов без пути, никогда не заключенные в "
  • в обратном порядке по дате последнего изменения из-за опции /O-D и без использования опции /TC (дата создания) или /TA (дата последнего доступа), что означает сначала самый новый измененный файл и последний самый старый измененный файл.

Вывод DIR записывается для обработки STDOUT запущенного фонового командного процесса.

2>nul перенаправляет вывод сообщения об ошибке с помощью DIR при отсутствии поиска файлав указанном направлениипопробуйте из дескриптора STDERR на устройство NUL , чтобы подавить это сообщение об ошибке.

Прочтите статью Microsoft о Использование операторов перенаправления команд для объяснения2>nul.Оператор перенаправления > должен быть экранирован с помощью символа вставки ^ в FOR командной строке, чтобы интерпретироваться как литеральный символ, когда интерпретатор команд Windows обрабатывает эту командную строку перед выполнением команды FOR , котораявыполняет встроенную командную строку dir в отдельном командном процессе, запущенном в фоновом режиме.

FOR захватывает все, что написано DIR для обработки STDOUT запущенного командного процесса, и обрабатывает этот вывод построчно после того, как запущенный cmd.exe завершил себя.

FOR игнорирует пустые строки, которые здесь не встречаются из-за DIR выводит список имен файлов без пустых строк из-за использования /B.

FOR будет по умолчанию разделять строку на подстроки (токены), используя обычный пробел и символ горизонтальной табуляции в качестве разделителей.После этого разбиения подстроки FOR по умолчанию проверит, начинается ли первая подстрока с символом конца строки по умолчанию ;, и в этом случае строка будет игнорироваться как пустая строка.В противном случае FOR назначит строку с пробелом / символом табуляции для указанной переменной цикла I и выполнит командные строки в блоке команд между ( и совпадением ).

Имя файла может быть, например, ;Test File!.log, то есть имя файла, начинающееся с пробела и точки с запятой и содержащее еще один пробел и восклицательный знак.Такое имя файла будет разделено на ;Test (без пробела в начале) и File!.log, а затем игнорируется FOR , поскольку ;Test начинается с точки с запятой.

ForПо этой причине символ конца строки переопределяется с точки с запятой по умолчанию на вертикальную черту с eol=|, то есть символом, который не может содержать имя файла или папки в соответствии с документацией Microsoft о Именование файлов, путей и пространств имен .А поведение разделения строк отключено с помощью delims= в конце строки аргумента параметров после for /F, которая определяет пустой список разделителей.Таким образом, имя файла, выводимое DIR , присваивается переменной цикла I без каких-либо изменений, даже если это очень необычное имя для файла.

Файл, имя и расширение которого ибез указания пути для переменной переменная I копируется с помощью команды XCOPY в указанный целевой каталог с сохранением его имени и расширения.

XCOPY используется здесь вместоиз COPY по следующим причинам:

  1. XCOPY создает полный путь к целевому каталогу, если он еще не существует.
    COPY никогда не создает структуру каталогов для целевого каталога.
  2. XCOPY перезаписывает используемыми параметрами даже существующий файл в целевом каталоге, для которого установлен атрибут файла только для чтения. COPY никогда не перезаписывает файл, доступный только для чтения.

Пакетный файл не оценивает успех или ошибку процесса копирования файла, хотя это также возможно при использовании дополнительной командыстрока типа if errorlevel 1 ....

Следующая строка немного сложна для начинающих при записи пакетных файлов.

Командный процессор Windows cmd.exe анализирует весь блок команд, начиная с (вплоть до совпадения ) и заменяет в этом блоке команд все вхождения ссылок на переменные среды %variable% текущими значениями указанных переменных среды перед выполнением команды FOR , используя этот блок команд.Это поведение не хорошо в случае изменения значения переменной среды в таком командном блоке и оценки измененного значения переменной среды в том же командном блоке, как это сделано здесь для значения xx переменной среды FileCount.

См. Также Как интерпретатор сценариев команд Windows (CMD.EXE) анализирует сценарии?

Стандартное решение использует отложенное расширение , как объяснено с помощью команды SET на примере IF и FOR при запуске в окне командной строки set /?. Но это приведет здесь к интерпретации всех восклицательных знаков в имени файла, присвоенных переменной цикла I, как начала / конца отложенной ссылки на переменную расширенного окружения, а не как буквальный символ имени файла. Таким образом, цикл FOR не будет работать должным образом только из-за ! в именах файлов или путях каталогов.

Другое решение заключается в использовании команды CALL to SET переменной среды и ссылки на значение переменной среды с двумя знаками процента на каждой стороне вместо одного. Командная строка

call set "FileCount=%%FileCount:~1%%"

изменяется при разборе всего блока команд перед запуском FOR в

call set "FileCount=%FileCount:~1%"

Команда CALL при каждой итерации цикла приводит к повторному синтаксическому анализу командной строки на cmd.exe и т. Д. В первом (новейшем) файле выполняется команда SET с "FileCount=x" в качестве строки аргумента, поскольку есть только один x после первого символа строки текущего значения, а во втором файле с "FileCount=", поскольку теперь нет больше символа после первого x, который отменяет определение переменной среды FileCount .

Таким образом, после копирования второго файла переменная среды FileCount больше не определяется, что приводит к тому, что условие IF выполняется, и поэтому командный процессор Windows выполняет команду GOTO для продолжения выполнение командного файла больше не с циклом FOR , а в строке ниже строки с меткой FileCopyDone. Таким образом, цикл FOR завершается после копирования второго новейшего файла в указанный целевой каталог.

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

@echo off
setlocal EnableExtensions EnableDelayedExpansion
set FileCount=2
set "SourcePath=C:\source_location"
set "TargetPath=D:\target_location"

set "SourcePath=%SourcePath:/=\%"
set "TargetPath=%TargetPath:/=\%"

if not "%SourcePath:~-1%" == "\" set "SourcePath=%SourcePath%\"
if not "%TargetPath:~-1%" == "\" set "TargetPath=%TargetPath%\"

for /F "eol=| delims=" %%I in ('dir "%SourcePath%" /A-D /B /O-D 2^>nul') do (
    %SystemRoot%\System32\xcopy.exe "%SourcePath%%%I" "%TargetPath%" /C /I /Q /H /R /Y >nul
    set /A FileCount-=1
    if !FileCount! == 0 goto FileCopyDone
)

:FileCopyDone
rem Other commands can be inserted here.
endlocal

Существует также еще одно решение без использования отложенного расширения, которое я видел на этот ответ , написанный Compo .

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FileCount=2"
set "SourcePath=C:\source_location"
set "TargetPath=D:\target_location"

set "SourcePath=%SourcePath:/=\%"
set "TargetPath=%TargetPath:/=\%"

if not "%SourcePath:~-1%" == "\" set "SourcePath=%SourcePath%\"
if not "%TargetPath:~-1%" == "\" set "TargetPath=%TargetPath%\"

for /F "tokens=1* delims=:" %%H in ('dir "%SourcePath%" /A-D /B /O-D 2^>nul ^| %SystemRoot%\System32\findstr.exe /N "^"') do (
    %SystemRoot%\System32\xcopy.exe "%SourcePath%%%I" "%TargetPath%" /C /I /Q /H /R /Y >nul
    if %FileCount% == %%H goto FileCopyDone
)

:FileCopyDone
rem Other commands can be inserted here.
endlocal

Вывод DIR перенаправляется на FINDSTR , который выводит все строки без фильтрации, поскольку строка поиска регулярного выражения с ^ приводит к положительному совпадению на всех строках. Но имена файлов выводятся с увеличенным (строка) номером и двоеточием в начале из-за опции /N.

Итак, вывод DIR как

Newest File.log
Other File.log
Oldest File.log

изменяется FINDSTR на

1:Newest File.log
2:Other File.log
3:Oldest File.log

Команда FOR с параметрами tokens=1* delims=: разбивает каждую строку на номер строки / файла слева от двоеточия, назначенного переменной цикла H, и имя файла справа от двоеточия, назначенного следующему циклу переменная I согласно ASCII табл.

Файл копируется, и затем выполняется сравнение строк с учетом регистра, чтобы проверить, равен ли номер файла строковому значению, присвоенному переменной окружения FileCount. В одинаковых числовых строках цикл завершается с помощью команды GOTO , поскольку определенное количество новейших файлов уже скопировано в целевой объект.

Чтобы понять используемые команды и то, как они работают, откройте окно командной строки, выполните там следующие команды и полностью прочитайте все страницы справки, отображаемые для каждой команды.

  • call /?
  • dir /?
  • echo /?
  • endlocal /?
  • for /?
  • findstr /?
  • goto /?
  • if /?
  • rem /?
  • set /?
  • setlocal /?
  • xcopy /?
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...