0

In a text file I have 1000 of rows, each row has below data:

ABCDqwqqwq321890821dsapodsaidadopd-9sa-9asd-9sa00sahjkhjsakdhdsddsad                           JhKyy120320171212

I need to delete the characters (90 characters onwards) from each line and save file as Test_DDMMYYYY.txt.

Below is my code, I'm not able to get the output.

Any suggestions please?

@echo off &setlocal
(for /f "delims=" %%a in (*.*txt) do (
    set "line=%%a"
    setlocal enabledelayedexpansion
    set "line=!line:~,90!"
    echo(!line!
    endlocal
))>Test_DDMMYYYY.txt

Also using this code for renaming the txt file:

@echo off
for /f "delims=" %%a in ('wmic OS Get localdatetime  ^| find "."') do set "dt=%%a"
set "YY=%dt:~2,2%"
set "YYYY=%dt:~0,4%"
set "MM=%dt:~4,2%"
set "DD=%dt:~6,2%"

set datestamp=%DD%%MM%%YYYY%
set fullstamp=%DD%%MM%%YYYY%

ren "C:\test\Test_.txt" "Test_%fullstamp%.txt"
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Anil
  • 11
  • 4
  • Please provide a **specific question title**! The one you stated is completely useless! Consult this: [ask] – aschipfl May 13 '17 at 13:16
  • without trying, three lines catched my attention: `set "line=!line:~,90!"`, `))>Test_DDMMYYYY.txt` and `ren "C:\test\Test_.txt" "Test_%fullstamp%.txt"` – Stephan May 13 '17 at 14:50
  • if I specifically mention any file name here (*.* txt) do ( I get the output file with all the required data, for e.g. @echo off &setlocal (for /f "delims=" %%a in (test.txt) do ( – Anil May 13 '17 at 18:45
  • @ Mofi, below code worked perfectly fine, thank you very much. One more small help i need is that I want to use the same file name as the original fine name e.g. Test_05_14_2017_01 (Test_MM_DD_YYYY_Version ID " – Anil May 14 '17 at 15:04

1 Answers1

0

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.

Community
  • 1
  • 1
Mofi
  • 46,139
  • 17
  • 80
  • 143