1

I have a problem with a batch file I am trying to write.

Goal: Check if logfile.log exists and if not create it. Otherwise file size should be checked if the file already exists. If the log file size is below a certain amount "do nothing", else copy the log and save it with a new name and reset the content of the actual log file.

Problem: For some reason the batch is not working anymore when I use the exist check and the size check.

Both operations separated are working without a problem. Everything is working fine if I remove the exist condition and keep the rest of the code and logfile.log exists already. Log files with a timestamp are created if the size is too large and the actual file is reset as expected.

set LOGFILE=%batdir%logfile.log
set maxbytesize=4000

if exist %LOGFILE% (
    for /F "usebackq" %%A IN ('%LOGFILE%') DO set size=%%~zA
    if %size% GTR %maxbytesize% (
        copy %LOGFILE% %LOGFILE%_%timestamp%
        :: overwrite existing file with ">"
        >%LOGFILE% echo Timestamp: %timestamplog%
        >>%LOGFILE% echo old log: %LOGFILE%_%timestamp%
    )
) else (
    echo Do Nothing >>%LOGFILE%
)
Mofi
  • 38,783
  • 14
  • 62
  • 115
Thomas
  • 13
  • 4

1 Answers1

2

This issue is caused by the classic delayed expansion trap every beginner in batch file writing walk into who has never read help of command SET output on running in a command prompt window set /?.

A command block starting with ( and ending with matching ) is parsed by Windows command processor before execution of the command making use of this command block. During the command block parsing all occurrences of %variable% are replaced by the current values of theĀ referenced environment variables. This can be seen on debugging a batch file.
Please see also: How does the Windows Command Interpreter (CMD.EXE) parse scripts?

So in this case %size% is replaced by nothing because of this environment variable most likely does not exist on execution of the batch file before the command IF is executed which is checking existence of the log file. The definition of environment variable size inside the command block on log file really existing does not become effective for %size% already replaced by an empty string during command block parsing phase.

The most likely best solution in this case is avoiding all command blocks. Then delayed environment variable expansion is also not needed.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "LogFile=%~dpn0.log"
set "MaxLogFileSize=4000"

if not exist "%LogFile%" echo Do Nothing>>"%LogFile%"& goto DoMore

for %%I in ("%LogFile%") do set "LogFileSize=%%~zI"
if %LogFileSize% LSS %MaxLogFileSize% goto DoMore

for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "TimeStamp=%%I"
set "FileTimeStamp=%TimeStamp:~0,4%-%TimeStamp:~4,2%-%TimeStamp:~6,2%_%TimeStamp:~8,2%-%TimeStamp:~10,2%-%TimeStamp:~12,2%"
set "TextTimeStamp=%TimeStamp:~0,4%-%TimeStamp:~4,2%-%TimeStamp:~6,2% %TimeStamp:~8,2%:%TimeStamp:~10,2%:%TimeStamp:~12,2%"

move /Y "%LogFile%" "%~dpn0_%FileTimeStamp%.log"
>"%LogFile%" echo Time stamp: %TextTimeStamp%
>>"%LogFile%" echo Old log: %~n0_%FileTimeStamp%.log

:DoMore
rem Add here more command lines using "%LogFile%".
endlocal

It is in my point of view not a good idea to limit size of a log file and additionally keep the log file on exceeding the limit with a file name containing current local date and time. This results in getting more and more log files on storage media and file size limitation of log file does not prevent using more and more storage space.

It would be better to simply move already too large log file with fixed file name overwriting already existing file with that file name.

Example:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "LogFile=%~dpn0.log"
set "MaxLogFileSize=4000"
set "OldLogFile=%~dpn0_old.log"

if exist "%LogFile%" for %%I in ("%LogFile%") do if %%~zI GTR %MaxLogFileSize% move /Y "%LogFile%" "%OldLogFile%"

rem Add here more command lines using "%LogFile%".
endlocal

The batch file overwrites the *_old.log file with current log file on exceeding log file limit. So the current log file contains the logged information about last actions and the file *_old.log contains archived logged information recorded within a period of time depending on how much information is logged on each execution of the batch file and how often the batch file is executed within a certain time span. The maximum storage space ever needed is about two times value of MaxLogFileSize and nobody has to periodically delete older log files never viewed by anybody in future anymore.

Note: Windows command processor uses 32-bit signed integer arithmetic. So value of MaxLogFileSize must be enough bytes lower than maximum positive 32-bit signed integer which is 2 GiB or 2147483647 in bytes to prevent that the current log file becomes ever greater or equal 2147483648 bytes.

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.

  • call /? ... explains %~dpn0 which is expanded to drive, path and name of batch file without file extension.
  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • move /?
  • rem /?
  • set /?
  • setlocal /?
  • wmic /?
  • wmic os /?
  • wmic os get /?
  • wmic os get localdatetime /?

I recommend also reading:

Mofi
  • 38,783
  • 14
  • 62
  • 115