The batch code for copying each line not being empty and not starting with a semicolon to a new file with with local date in format DDMMYYYY
in file name with truncating each line after the first 90 characters could be for example:
@echo off
if not exist "Test.txt" goto :EOF
setlocal EnableExtensions EnableDelayedExpansion
for /F "tokens=2 delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "LocalDate=%%I"
set "FileDate=%LocalDate:~6,2%%LocalDate:~4,2%%LocalDate:~0,4%
del "Test_%FileDate%.txt" 2>nul
for /F "usebackq delims=" %%I in ("Test.txt") do set "Line=%%I" & echo !Line:~0,90!>>"Test_%FileDate%.txt"
endlocal
The command
%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE
outputs UTF-16 Little Endian encoded for example:
LocalDateTime=20170513195342.921000+120
So the first line is an empty line and the second line contains the local date in format YYYYMMDD
after the equal sign independent on region and languages settings defined for the current user account. And there are output 2 more empty lines.
Command FOR has some problems on parsing UTF-16 LE encoded output which results in interpreting last empty line not as empty line, but as a line containing just a carriage return. Details about this issue can be found for example in answer on Batch: How to correct variable overwriting misbehavior when parsing output.
The command FOR as used here splits each line up into two substrings (tokens) using the equal sign as delimiter because of delims==
and assigns just the second string to loop variable I
because of tokens=2
. This means that 20170513195342.921000+120
is assigned to environment variable LocalDate
.
The issue with last empty line being interpreted as line with a carriage return is worked around because of tokens=2
because the line with just carriage return can't be split up into two tokens and for that reason the misinterpreted last empty line of output of WMIC is also ignored here by FOR.
The local date/time string is reformatted to just DDMMYYYY
as requested by using command SET with 3 string substitutions.
Hint: File names using YYYYMMDD
or better readable YYYY-MM-DD
are automatically sorted by date when being displayed sorted by file name. Therefore YYYYMMDD
or YYYY-MM-DD
would be better than DDMMYYYY
as date format in file name.
Then the output file is deleted if existing already with redirecting the error message on output file not existing to device NUL
to suppress it.
The second FOR parses the lines of file Test.txt
even with enclosing the file name in double quotes because of option usebackq
. Empty lines are skipped as also lines starting with a semicolon. But all other lines are processed without splitting the lines because of option delims=
which turns off default splitting on spaces and horizontal tabs and processing further only the first substring. So each non empty line not starting with a semicolon is assigned to loop variable I
before processing the command line.
The line is next assigned to environment variable Line
.
Note 1: Because of enabled delayed expansion as needed next with this solution a line containing 1 or more exclamation marks would not be processed correct because of interpreting each exclamation mark as begin or end of a reference to an environment variable with delayed expansion. So a different batch code would be necessary if the file could contain also exclamation marks in first 90 characters of each line.
Note 2: The posted line in question from input file has only 68 characters and there was not posted what should be written for this line into output file. I hope that I understood the task correct.
With operator &
two commands are specified on one command line to execute after the command set "Line=%%I"
one more command to output just the first 90 characters from input file with redirecting this output from handle STDOUT to file with local date in file name with appending this line to existing output file contents.
The truncation of the line to first 90 characters within FOR loop requires delayed expansion or a different code like using a subroutine.
Once the input file Test.txt
is completely processed line by line, the previous command process environment is restored and batch file execution terminates.
Here is an alternate solution which avoids the usage of delayed expansion:
@echo off
if not exist "Test.txt" goto :EOF
setlocal EnableExtensions DisableDelayedExpansion
for /F "tokens=2 delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "LocalDate=%%I"
set "FileDate=%LocalDate:~6,2%%LocalDate:~4,2%%LocalDate:~0,4%
del "Test_%FileDate%.txt" 2>nul
for /F "usebackq delims=" %%I in ("Test.txt") do set "Line=%%I" & call :OutputLine
endlocal
goto :EOF
:OutputLine
>>"Test_%FileDate%.txt" echo %Line:~0,90%
goto :EOF
A subroutine is used here to output just the first 90 characters of each line to the output file.
The redirection operator >>
and the output file name are specified first on command line because of
echo %Line:~0,90%>>"Test_%FileDate%.txt"
could result with immediate environment variable expansion and a line ending with a space and a number in range 1
to 9
in wrong file output.
This solution also does not work when a line to output contains characters with special meaning for Windows command interpreter like &
, |
, <
, >
, ... Windows command interpreter is not really designed for text editing. Text editors are designed for text editing.
The first solution rewritten to process each *.txt file in current directory except the output file also written into current directory.
@echo off
setlocal EnableExtensions EnableDelayedExpansion
for /F "tokens=2 delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "LocalDate=%%I"
set "FileDate=%LocalDate:~6,2%%LocalDate:~4,2%%LocalDate:~0,4%
del "Test_%FileDate%.txt" 2>nul
for /F "delims=" %%T in ('dir *.txt /A-D /B 2^>nul') do for /F "usebackq delims=" %%I in ("%%T") do set "Line=%%I" & echo !Line:~0,90!>>"Test_%FileDate%.txt"
endlocal
The file contents processing FOR loop is nested within one more FOR loop which runs command DIR listing all *.txt files (and not directories) because of /A-D
in bare format (file name and file extension only without path) because of /B
.
This list of file names of command DIR is processed line by line by outer FOR without splitting up the file names and running the inner FOR loop which processes the lines of the text file.
2^>nul
redirects the error message output by DIR if no *.txt file found in current directory to device NUL to suppress it. The redirection operator >
must be escaped here with ^
to be interpreted by Windows command interpreter as literal character on parsing FOR command line, but as redirection operator on executing DIR command line in one more command process started by FOR to execute the command.
2>nul
in the command (line) to execute by FOR would result in an exit of batch execution because of a syntax error because a redirection for FOR can't be specified at this position in the command line.
Another variant which processes also each *.txt file in current directory.
@echo off
setlocal EnableExtensions EnableDelayedExpansion
for /F "delims=" %%T in ('dir *.txt /A-D /B 2^>nul') do (
del "%%~nT.tmp" 2>nul
for /F "usebackq delims=" %%I in ("%%T") do set "Line=%%I" & echo !Line:~0,90!>>"%%~nT.tmp"
if exist "%%~nT.tmp" (
%SystemRoot%\System32\fc.exe "%%~nT.tmp" "%%T" /A >nul
if errorlevel 1 ( move /Y "%%~nT.tmp" "%%T" ) else ( del "%%~nT.tmp" )
)
)
endlocal
The truncated lines of each *.txt file are written into a *.tmp file with same name as the current *.txt file instead of writing all truncated lines into same output file.
After processing a *.txt file, the *.tmp file replaces the *.txt file if its content is different to content of the *.txt file. Otherwise the temporary file is deleted on *.tmp file being equal the *.txt file and the text file is kept unmodified.
So finally all *.txt files in current directory have no line longer 90 characters.
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 /?
del /?
echo /?
endlocal /?
fc /?
for /?
goto /?
if /?
move /?
set /?
setlocal /?
wmic /?
wmic os /?
wmic os get /?
wmic os get localdatetime /?
Read also Single line with multiple commands using Windows batch file and the Microsoft article about Using Command Redirection Operators.