如何将两个最新的日志文件复制到另一个文件夹? [英] How to copy the two most recent log files to another folder?

查看:149
本文介绍了如何将两个最新的日志文件复制到另一个文件夹?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将两个最新错误日志从源位置复制到另一个易于访问的文件夹中。我在此处的 Magoo帖子中找到了以下代码,其说明是替换 echo %% i 和相应的复制命令。由于某种原因,我很难过。

I am trying to copy the two most recent error logs from a source location to another folder which is easier to access. I found the code below on Magoo's post here and the instructions were to replace echo %%i with the appropriate copy command. I am having a hard time with that for some reason.

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


推荐答案

此批处理文件可用于仅将指定源目录中的两个最新文件复制到指定目标目录的任务,而与该批处理文件执行时的当前目录无关。

This batch file can be used for the task to copy just the two newest files in specified source directory to the specified target directory independent on which directory is the current directory on execution of the batch file.

@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 命令的详细信息以及在使用这两个命令的背景下会发生什么。

The batch file first sets up a local environment with enabled command extensions as needed here and with delayed environment variable expansion disabled to be able to copy also files of which full qualified file name (drive + path + name + extension) contain one or more exclamation marks. Please read this answer for details about the commands SETLOCAL and ENDLOCAL and what happens in background on using these two commands.

要复制的文件数取决于 x 个字符的数量。分配给环境变量 FileCount 的字符串。 xx 表示复制两个文件, xxxx 表示复制四个文件。分配给环境变量 FileCount 的字符串中使用哪个字符并不重要,字符串的长度必须至少为一个字符。

The number of files to copy is determined by the number of x characters of the string assigned to environment variable FileCount. xx means copying two files and xxxx would be for copying four files. It does not really matter which character is used in the string assigned to environment variable FileCount, the length of the string matters which must be at least one character.

然后,该批处理文件确保在源路径和目标路径中使用 \ ,因为这是Windows上的目录分隔符,而不是 / ,就像在Linux和Mac上一样。

Then the batch file makes sure that \ is used in source and target path because this is the directory separator on Windows and not / as it is on Linux and Mac.

下一个源和目标路径在批处理文件中定义。这两个环境变量也可以动态定义,而不是通过将传递给批处理文件的第一个和第二个参数分配给这两个环境变量来固定地定义。

Next source and target path are defined in batch file. These two environment variables could be also defined dynamically instead of fixed by getting assigned the first and second argument passed to the batch file to these two environment variables.

该批处理文件是为源路径编写的总是以Windows目录分隔符 \ 结尾,因此,批处理文件确保源路径的最后一个字符确实是反斜杠。

The batch file is written for source path always ending with Windows directory separator \ and for that reason the batch file makes sure that the last character of source path is really a backslash.

目标路径必须以反斜杠结尾。这对将其用作命令 XCOPY 的目标字符串非常重要,正如我在 batch文件中的答案中非常详细地解释的那样询问文件或文件夹。出于这个原因,批处理文件确保目标路径也以反斜杠结尾。

The target path must end with a backslash. That is very important on using it as target string for command XCOPY as explained very detailed in my answer on batch file asks for file or folder. For that reason the batch file makes sure that target path also ends with a backslash.

命令 FOR 和选项 / F 使用%ComSpec%/ c '之间指定的命令行开始新的命令过程在后台进行进一步的论证。因此,由 FOR 执行的操作具有通常的Windows安装路径:

The command FOR with option /F starts a new command process with %ComSpec% /c and the command line specified between ' as further arguments in background. So executed by FOR is with usual Windows installation path:

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

DIR ,由后台命令进程搜索指定的参数

DIR executed by background command process searches with the specified arguments


  • 在指定的源目录中

  • 用于文件(由于选项 / AD (属性而非目录)

  • 匹配默认通配符模式 * (全部)

  • in the specified source directory
  • for files because of option /A-D (attribute not directory)
  • matching the default wildcard pattern * (all)

并由于选项 / B

and outputs


  • c $ c>只是不带路径的文件名,因此永远都不能包含在 c中

  • 由于选项<$而在上次修改日期之前被反向排序c $ c> / OD 且未使用选项 / TC (创建日期)或 / TA (最后访问日期),表示第一个最新的修改文件,最后一个最旧的修改文件。

  • in bare format because of option /B just the file names without path never enclosed in "
  • ordered reverse by last modification date because of option /O-D and not using option /TC (creation date) or /TA (last access date) which means first the newest modified file and last the oldest modified file.

DIR的输出 >被编写为处理已启动的后台命令过程的 STDOUT

The output by DIR is written to handle STDOUT of the started background command process.

2> nul 重定向 DIR 输出的错误消息,原因是在指定的目录中没有找到从句柄 STDERR 到设备 NUL 的文件来抑制此错误消息。

2>nul redirects the error message output by DIR on not finding any file in specified directory from handle STDERR to device NUL to suppress this error message.

阅读有关使用命令重定向运算符来解释 2> nul 。重定向操作符> 必须在 FOR 命令行上使用插入符号 ^ 进行转义,以转至Windows命令解释器在执行命令 FOR 之前处理Windows命令行时,该字符将被解释为文字字符,该命令在单独启动的命令过程中执行嵌入式 dir 命令行

Read the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line in a separate command process started in background.

FOR 捕获由 DIR 编写的所有内容,以处理已开始的命令流程的 STDOUT 此输出在开始 cmd.exe 终止后逐行显示。

FOR captures everything written by DIR to handle STDOUT of started command process and processes this output line by line after started cmd.exe terminated itself.

FOR 忽略空行由于使用 / B ,因此 DIR 不会在此处出现文件名列表,因此不会出现空行。

FOR ignores empty lines which do not occur here because of DIR outputs the list of file names without empty lines because of using /B.

FOR 默认情况下会使用常规空格和水平制表符作为分隔符,将一行拆分为子字符串(令牌)。在完成此子字符串拆分之后, FOR 将默认检查第一个子字符串是否以默认的行尾字符开始; ,在这种情况下,该行将是像空行一样被忽略。否则, FOR 会将第一个空格/制表符分隔的字符串分配给指定的循环变量 I ,并在<$ c之间执行命令块中的命令行$ c>(并匹配

FOR would split up by default a line into substrings (tokens) using normal space and horizontal tab character as delimiters. After this substring splitting is done FOR would by default check if the first substring starts with default end of line character ; in which case the line would be ignored like an empty line. Otherwise FOR would assign first space/tab delimited string to the specified loop variable I and would execute the command lines in the command block between ( and matching ).

文件名例如可以是; Test File!.log ,即文件名,以空格和分号开头,还包含一个空格和一个感叹号。这样的文件名将拆分为;测试(开头没有空格)和 File!.log ,然后再拆分由于而被 FOR 忽略;测试以分号开头。

A file name could be for example ;Test File!.log, i.e. a file name starting with a space and a semicolon and containing one more space and an exclamation mark. Such a file name would be split up to ;Test (without space at beginning) and File!.log and next ignored by FOR because of ;Test starts with a semicolon.

因此,行尾使用 eol = | 将字符从默认分号重新定义为竖线,根据Microsoft关于命名文件,路径和命名空间。在/ F 的之后的选项参数字符串末尾使用 delims = 禁用了行拆分行为,它定义了一个空列表定界符。因此,将 DIR 输出的文件名分配给循环变量 I ,即使它是一个非常不寻常的文件名,也无需进行任何修改。

For that reason the end of line character is redefined from default semicolon to a vertical bar with eol=| which is a character no file or folder name can contain according to Microsoft documentation about Naming Files, Paths, and Namespaces. And line splitting behavior is disabled with delims= at end of options argument string after for /F which defines an empty list of delimiters. So the file name as output by DIR is assigned to loop variable I without any modification even on being a very unusual name for a file.

将名称和扩展名且没有路径的文件分配给循环变量 I 的文件使用命令 XCOPY 复制

The file of which name and extension and without path is assigned to loop variable I is copied with command XCOPY to the specified target directory with keeping its name and extension.

XCOPY 而不是 COPY ,原因如下:


  1. XCOPY 创建目标目录的整个目录路径(如果尚不存在)。

    COPY 永远不会创建目标目录的目录结构。

  2. XCOPY 会覆盖使用的参数,即使目标目录中已有文件已设置为只读文件属性。 COPY 永远不会覆盖只读文件。

  1. XCOPY creates the entire directory path to target directory if not already existing.
    COPY never creates the directory structure to target directory.
  2. XCOPY overwrites with the used parameters even an already existing file in target directory having set the read-only file attribute. COPY overwrites never a read-only file.

文件复制过程的成功与否不由批处理来评估文件,尽管如果错误级别为1 ... ,也可以使用其他命令行,例如

The success or error of the file copying process is not evaluated by the batch file although that would be also possible with an additional command line like if errorlevel 1 ....

下一行是

Windows命令处理器 cmd.exe 解析以<$ c开头的整个命令块$ c>(直至匹配的并在此命令中替换所有出现的%variable% FOR 之前,通过引用的环境变量的当前值$ c>环境变量的引用将利用此命令块。如果在这样的命令块中修改环境变量的值并像在此对值 xx 所做的那样在同一命令块中评估修改后的环境变量值,则此行为不好环境变量 FileCount

Windows command processor cmd.exe parses the entire command block starting with ( up to matching ) and replaces in this command block all occurrences of %variable% environment variable references by the current values of the referenced environment variables before the command FOR is executed make use of this command block. This behavior is not good in case of modifying the value of an environment variable within such a command block and evaluating the modified environment variable value in same command block as done here on value xx of environment variable FileCount.

另请参见 Windows命令解释器(CMD.EXE)如何解析脚本?

标准解决方案使用的是延迟扩展,如 IF 上的命令 SET FOR 所帮助在命令提示符窗口 set /?中运行的示例输出。但这会导致将分配给循环变量 I 的文件名中的所有感叹号解释为延迟的扩展环境变量引用的开始/结束而不是文件的文字字符名称。因此,仅由于文件名或目录路径中的 FOR 循环将无法按预期工作。

The standard solution is using delayed expansion as explained by help of command SET on an IF and a FOR example output on running in a command prompt window set /?. But this would result here in interpreting all exclamation marks in file name assigned to loop variable I as begin/end of a delayed expanded environment variable reference and not as literal character of the file name. So the FOR loop would not work as expected just because of ! in file names or directory paths.

另一种解决方案是使用命令 CALL SET 一个环境变量,并引用环境变量值,该值的两边都带有两个百分号而不是一个。命令行

Another solution is using command CALL to SET an environment variable and reference the environment variable value with two percent signs on each side instead of just one. The command line

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

在运行 FOR

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

命令 CALL 在循环的每次迭代期间在第二次解析命令行时产生通过 cmd.exe 等,第一个(最新)文件使用" FileCount = x"执行命令 SET 作为参数字符串,因为在当前值字符串的第一个字符之后,并且在第二个文件中,只有<< c $ c> x 且具有 FileCount =" ,因为第一个 x 之后不再有字符,这会取消定义环境变量 FileCount

The command CALL results during each iteration of the loop in parsing the command line a second time by cmd.exe and so on first (newest) file the command SET is executed with "FileCount=x" as argument string as there is just one x after first character of current value string and on second file with "FileCount=" as there is now no more character after first x which undefines the environment variable FileCount.

因此,在复制了第二个文件后,不再定义环境变量 FileCount ,结果为 IF 条件为true,因此Windows命令处理器执行命令 GOTO 以继续执行批处理文件,而不再通过 FOR 循环,而是在该行下面的行中标签为 FileCopyDone 。因此,在将第二个最新文件复制到指定目标目录后,退出 FOR 循环。

So after second file was copied the environment variable FileCount is not defined anymore which results in IF condition is true and so command GOTO is executed by Windows command processor to continue execution of the batch file not anymore with the FOR loop, but on the line below the line with label FileCopyDone. So the FOR loop is exited after copying second newest file to specified target directory.

以下是使用延迟扩展的解决方案,仅当两个目录路径和所有要复制的文件不包含感叹号。

Here is the solution using delayed expansion working only if the two directory paths and all files to copy do not contain an exclamation mark.

@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 编写。。 p>

There is one more solution also without using delayed expansion which I saw on this answer written by 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 ,文件名的输出以递增(行)号和开头的冒号开头。

The output of DIR is redirected to FINDSTR which outputs all lines unfiltered because of the regular expression search string with just ^ results in a positive match on all lines. But the file names are output with an incremented (line) number and a colon at beginning because of option /N.

因此 DIR 的输出,例如

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

FINDSTR 修改为

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

带有选项 tokens = 1 * delims =:的命令 FOR 分配给循环变量 H 的冒号的文件号和分配给下一个循环变量 I 的冒号的文件名根据 ASCII 表。

The command FOR with the options tokens=1* delims=: splits up each line into the line/file number left to the colon assigned to loop variable H and the file name right to colon assigned to next loop variable I according to ASCII table.

复制文件,然后进行区分大小写的字符串比较,以检查文件数是否等于分配给环境变量 FileCount 的字符串值。在相等数目的字符串上,由于已将已定义数量的最新文件复制到目标,因此使用命令 GOTO 退出循环。

The file is copied and next a case-sensitive string comparison is done to check if the number of the file is equal the string value assigned to environment variable FileCount. On equal number strings the loop is exited with command GOTO because of the defined number of newest files are copied already to the target.

用于了解所使用的命令和它们的工作方式,打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.


  • 通话/?

  • dir /?

  • echo /?

  • endlocal /?

  • 用于/?

  • findstr /?

  • goto /?
  • 如果/?
  • c>

  • rem /?

  • set /?

  • setlocal /?

  • xcopy /?

  • call /?
  • dir /?
  • echo /?
  • endlocal /?
  • for /?
  • findstr /?
  • goto /?
  • if /?
  • rem /?
  • set /?
  • setlocal /?
  • xcopy /?

这篇关于如何将两个最新的日志文件复制到另一个文件夹?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆