批处理文件日志功能,用于将命令输出打印到日志文件和屏幕

时间:2015-08-30 04:39:14

标签: batch-file

我发现有一些类似于这个问题的主题,但不完全是我想要的,所以我提出了这个话题。

我想创建一个日志功能,用于将消息打印到格式化日志文件和控制台输出。功能如下:

:LOGDEBUG
@echo DEBUG: %~1
if NOT EXIST %LOG_FILE% exit /b 1
@echo [%date - %time%] DEBUG: %~1 >> %LOG_FILE% 2>&1
exit /b 0

我尝试使用它来打印命令执行输出,如果输出包含特殊字符,如"<"和">",此功能不能正常工作并提示"系统无法找到指定的文件"。我执行命令的代码如下:

for /f "usebackq delims=" %%a in (`dir c:\temp`) do (
    CALL :LOGDEBUG "%%a"
)

然而,当我使用" echo"直接命令而不是日志功能,输出可以在控制台上正确打印。如下代码:

for /f "usebackq delims=" %%a in (`dir c:\temp`) do (
    echo %%a
)

我可以知道是什么问题,如何使用日志功能正确打印输出?感谢

2 个答案:

答案 0 :(得分:1)

这是应该有效的批处理代码。

@echo off
setlocal EnableDelayedExpansion
set "LOG_FILE=C:\program.log"
del "%LOG_FILE%" 2>nul
for /F "delims=" %%a in ('dir "C:\temp\*" 2^>nul') do call :LOGDEBUG "%%a"
endlocal
goto :EOF

:LOGDEBUG
set "StringToOutput=%~1"
echo DEBUG: !StringToOutput!
echo [%DATE% - %TIME%] DEBUG: !StringToOutput!>>"%LOG_FILE%"
goto :EOF

启用第一个延迟环境变量扩展,并创建现有环境表的副本。下面解释了为什么这样做。

接下来,将具有完整路径的日志文件的名称分配给局部变量表中的环境变量。此路径可以在路径中包含或不包含1个或多个空格。如果已经存在以前的运行,则删除日志文件。如果要将新行附加到现有文件,则可以删除此代码。但是你应该在这种情况下添加代码,以避免日志文件永久增加,直到没有空闲存储空间为止。

FOR 命令执行命令 DIR 并处理写入标识符 DIR 输出的每一行。空白行被跳过。默认分隔符是空格,制表符和换行符。这里想要的是 DIR 的整行,默认的分隔符列表被替换为no,这意味着只保留换行符,并且循环变量%a总是被赋予整个非空行。

命令 DIR 的输出包含<>,如果命令处理器在未引用的行中找到,则将其解释为redirection operators。因此, DIR 输出的行被引用到子例程LOGDEBUG。在命令提示符窗口中执行cmd /?时,在命令提示符窗口中打印的最后一个帮助页面上列出了通常必须引用的字符。

循环完成后,将删除本地环境表,这意味着LOG_FILEStringToOutput也将被删除,并恢复以前的环境,这通常意味着在批量执行之前再次关闭延迟扩展退出并跳转到预定义标签到文件末尾。

子例程LOGDEBUG首先将传递的字符串分配给环境变量,而不需要包含引号,因为<>等行中包含特殊字符。

接下来,使用延迟扩展将行写入控制台窗口而不使用引号,否则<>将被解释为重定向运算符而不是字面意思。

同样的行也写入日志文件,并在行的开头插入日期和时间的差异。您错过了代码中date后的百分号。再次延迟扩展用于获取写入文件的<>字符的行,而不会被解释为重定向运算符。

重要的是,>>之前没有空格,否则日志文件中的每一行都会有一个尾随空格。 2>&1在此处无用,因为命令 echo 不会向 stderr 写入内容。

退出子程序时跳转到文件末尾,导致命令 FOR 处理下一行。

要了解使用的命令及其工作原理,请打开命令提示符窗口,执行以下命令,并完全阅读为每个命令显示的所有帮助页面。

  • call /?
  • del /?
  • dir /?
  • for /?
  • goto /?
  • set /?

当然可以直接在命令体 FOR 中完成所有输出而不使用子程序。

@echo off
setlocal EnableDelayedExpansion
set "LOG_FILE=C:\program.log"
del "%LOG_FILE%" 2>nul
for /F "delims=" %%a in ('dir "C:\temp\*" 2^>nul') do (
    echo DEBUG: %%a
    echo [!DATE! - !TIME!] DEBUG: %%a>>"%LOG_FILE%"
)
endlocal

此处需要延迟变量扩展,否则%DATE%%TIME%将由%LOG_FILE%等命令处理器在解析(和{{定义的整个块时1}}之前执行命令 FOR 会导致为日志文件的所有行写入相同的日期和时间。

答案 1 :(得分:1)

您已经回答了自己的问题:当我使用&#34; echo&#34;直接命令 ...

@ECHO OFF
SETLOCAL EnableExtensions
set "LOG_FILE=D:\tempx\program.log"     my testing value 
rem type NUL>"%LOG_FILE%"
for /f "usebackq delims=" %%a in (`dir d:\temp 2^>NUL`) do (
    CALL :LOGDEBUG "%%a"
)
rem type "%LOG_FILE%"
ENDLOCAL
exit /b

:LOGDEBUG
FOR %%A in ("%~1") do (
  @echo DEBUG: %%~A
  if NOT EXIST "%LOG_FILE%" exit /b 1
  @echo [%date% - %time%] DEBUG: %%~A >> "%LOG_FILE%" 2>&1
)
exit /b 0

资源(必读):

相关问题