如何创建一个输出到日志文件的批处理文件

How to create a batch file with output to a log file

我想创建从任务计划程序运行的批处理文件

要求:

  1. 30 天以内的文件应从主文件夹移至存档文件夹。
  2. 那么应该删除移动的存档文件。
  3. 它应该存储所有日志条目。

我编写了步骤 1 & 2(来自网络搜索),但是插入日志文件命令对我来说非常困难,因为我不了解批处理脚本。

步骤 12 的脚本:

forfiles /p "D:\Test" /m *.* /s /d -30 /c "cmd /c move @file E:\Test1"
forfiles /p "E:\Test1" /c "cmd /c del @path"

谁能告诉我如何使用上述 2 个命令创建日志文件。

日志文件应存储它移动和删除的所有文件名、日期和时间以及成功或失败。

首先将文件从驱动器D:移动到驱动器E:,这需要复制每个文件的数据,然后删除驱动器E:上的每个文件,这是完全没有意义的。直接在驱动器 D:.

上删除超过 29 天的文件要快

下面的批处理文件可用于记录每次文件删除成功或错误的文件删除任务。

@echo off
if "%~1" == "" goto RunForFiles
del /A /F %1 2>nul
(if not exist %1 (echo %DATE% %TIME% Deleted successfully:  %1) else echo %DATE% %TIME% Failed to delete file: %1)>>"E:\LogStoragePath\OldFileDeletionLog.txt"
exit /B

:RunForFiles
md "E:\LogStoragePath" 2>nul
del "E:\LogStoragePath\OldFileDeletionLog.txt" 2>nul
%SystemRoot%\System32\forfiles.exe /P "D:\Test" /M *.* /S /D -30 /C "%SystemRoot%\System32\cmd.exe /D /S /C \"if @isdir == FALSE \"%~f0\" @path\""

批处理文件首先检查是否在没有任何参数的情况下被调用,这是由计划任务启动的批处理文件的情况。在这种情况下,处理批处理文件会继续使用标签 RunForFiles.

下方的行

首先创建了日志文件的目录(树),但根本没有检查是否可以成功完成。命令 MD 在日志文件目录上输出的错误消息已被抑制,方法是将其从句柄 STDERR 重定向到设备 NUL2>nul 还抑制了由于其他原因(如缺少存储介质上的权限)而导致创建目录(树)时输出的错误消息。

接下来,如果日志文件根本不存在,则删除可能来自先前执行的日志文件,并通过 2>nul 抑制 DEL 输出的错误消息或由于缺少删除权限而无法完成删除(NTFS 权限、read-only 属性、当前在应用程序中打开的日志文件)。

然后执行FORFILES搜索

  • 用路径选项 /P
  • 指定的目录 D:\Test
  • 及其所有子目录,因为选项 /S
  • 用于文件系统条目(目录、文件和重新分析点)
  • 匹配通配符模式 *.*(任意)指定掩码选项 /M
  • 最后修改日期小于或等于 30 天
  • 执行选项/C指定的命令。

该命令导致 运行 多一个 Windows 命令处理器,带有选项 /D 忽略 AutoRun 注册表值和 /S 解释所有内容在下一个选项 /C 作为一个参数字符串与要执行的命令行和选项 /C 之后执行下一个指定的命令行并在完成执行后自行关闭。

如果 FORFILES 找到的当前文件系统条目具有最后修改日期,则启动的 Windows 命令处理器进程首先检查 case-sensitive 字符串比较早于 29 天不是目录。目录被忽略并导致立即关闭已启动 cmd.exe.

对于一个文件,接下来由启动 cmd.exe 当前处理的批处理文件执行,完整文件名包含在 " 作为参数。因此,cmd.exe 处理的批处理文件运行 forfiles.exe,它又启动一个 cmd.exe 来处理同一个批处理文件,但这次使用文件名作为批处理文件的参数。

这次批处理文件处理在第三个命令行上继续,该命令行使用带有选项 /A(所有属性)的命令 DEL 来否决隐式默认值 /A-H(除隐藏属性外的所有属性)也删除具有隐藏属性集的文件和选项 /F 以强制删除具有 read-only 属性集的文件。

在大多数情况下,文件删除很可能会成功。但是当前打开超过 29 天或特殊 NTFS 权限的文件的应用程序可能会导致文件删除失败。

因此使用IF条件来验证文件是否真的不再存在,在这种情况下输出成功消息以处理STDOUT 使用命令 ECHO 和动态变量 DATETIME。否则,如果文件删除失败,则会输出一条失败消息,其中包含 ECHO 以及 DATETIME 以处理 STDOUT。输出消息被重定向到指定的日志文件,并附加到这个日志文件上,该文件为每个要删除的文件打开、修改和关闭。

最后执行删除旧文件的批处理文件是使用命令 EXIT 使用选项 /B 退出批处理文件处理而不是整个 cmd.exe 正在处理这个批处理文件。由 forfiles.exe 启动的 cmd.exe 无事可做并关闭,这导致 forfiles.exe 搜索下一个符合指定条件的文件系统条目。

使用这个批处理文件,整个文件删除任务非常慢。对于此任务,使用由 Windows PowerShell 处理的小型 PowerShell 脚本肯定会好得多,它可以更快地执行此文件删除任务。

我还建议阅读我在 上的回答中的 最佳和简单的备份删除概念 一章。通常不建议简单地删除所有早于 X 天的文件而不检查是否存在较新的文件特别是如果要删除的文件是备份文件或定期执行任务的日志文件。使用与上次修改日期不同的删除策略在参考答案中发布的解决方案也比此处发布的解决方案快得多。

这也是上面的一个变体,首先将每个旧文件从 D:\Test 及其子目录移动到 E:\Test1 而没有 复制目标目录树记录文件移动成功或失败的目录,最后删除 E:\Test1 中的所有文件,记录文件删除的成功或失败。文件删除失败的可能性很小。

@echo off
if "%~1" == "" goto RunForFiles
move /Y %1 "E:\Test1\" >nul 2>nul
(if not exist %1 (echo %DATE% %TIME% Moved successfully:  %1) else echo %DATE% %TIME% Failed to move file: %1)>>"E:\LogStoragePath\OldFileMoveLog.txt"
exit /B

:RunForFiles
md "E:\Test1" 2>nul
md "E:\LogStoragePath" 2>nul
del "E:\LogStoragePath\OldFileMoveLog.txt" 2>nul
%SystemRoot%\System32\forfiles.exe /P "D:\Test" /M *.* /S /D -30 /C "%SystemRoot%\System32\cmd.exe /D /S /C \"if @isdir == FALSE \"%~f0\" @path\""
set "ProcessedFile="
(echo %DATE% %TIME%
 for %%I in ("E:\Test1\*") do (
    set "ProcessedFile=1"
    del /A /F "%%I" 2>nul
    if not exist "%%I" (echo Deleted successfully:  %%~nxI) else Failed to delete file: %%~nxI
))>"E:\LogStoragePath\OldFileDeletionLog.txt"
if exist "E:\LogStoragePath\OldFileDeletionLog.txt" if not defined ProcessedFile del "E:\LogStoragePath\OldFileDeletionLog.txt"

最后一个命令行在创建时删除了文件删除日志文件,但只包含日期和时间,因为之前没有文件被移动过,所以根本不需要删除任何文件。

为了了解使用的命令及其工作原理,请打开 command prompt window,在其中执行以下命令,并仔细阅读为每个命令显示的所有帮助页面。

  • cmd /?
  • del /?
  • echo /?
  • exit /?
  • for /?
  • forfiles /?
  • goto /?
  • if /?
  • md /?
  • move /?
  • set /?

另请参阅有关 Using command redirection operators 的 Microsoft 文档。