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%
)
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:
yyyy-MM-dd_HH-mm-ss
and for log file content in format yyyy-MM-dd HH:mm:ss
.