4

I am reading multiple lines from a data file and append it to another file. The issue is that some extra space is in output file at end of appended lines. It is mandatory to trim the trailing space according to my requirement because in original data file there is no space at end of the lines. I tried all possible things, but I still cannot achieve this one.

@echo off
setlocal enabledelayedexpansion
FOR /F "delims=" %%c IN (C:\Users\184863\Desktop\mydata.txt) DO ( 
echo %%c>>temp_data.txt 
)
endlocal

Options I tried:

  1. echo %%c>>temp_data.txt ... getting 1 space end of line

  2. set lines=%%c
    echo !lines!>>temp_data.txt ... getting 1 space end of line

  3. echo !lines:~0,-1!>>temp_data.txt ... last char of the line trimmed

  4. set lines=!lines: =!
    echo !lines!>>temp_data.txt ... all spaces inside the line are also trimmed (need to trim only end of the line, which is not present in original data file)

Mofi
  • 46,139
  • 17
  • 80
  • 143
Munu
  • 103
  • 5
  • 15

3 Answers3

5

There is a trailing space at end of the echo line as Magoo wrote already which is not ignored by ECHO. This trailing space is also output by ECHO after %%c.

A redirection is usually written at end of a command line, but it can be written anywhere. It is also possible to write the redirection at beginning as shown below or somewhere in the middle as it can be seen on FOR command line in this answer. Parsing of an ECHO command line is different to all other command lines as a space character outside a double quoted string is not interpreted as argument separator and for that reason each space character in ECHO command line matters and is output by ECHO including those before redirection operators like >.

This can be seen easily by

  • creating a batch file with just echo Test>Test.txt  with a trailing space after Test.txt,
  • opening a command prompt window, and
  • running this batch file from within command prompt window.

Output is echo Test  1>Test.txt. So > is replaced by Windows command interpreter by  1> (space, one, right angle bracket) and additionally moved to end of line. This movement on ECHO command line results in originally trailing space being moved left after the text Test and is therefore also output by ECHO.

This command line modification during preprocessing of the entire command block can be seen also by running original posted batch code without @echo off from within a command prompt window to debug the batch file. Windows command interpreter outputs with mydata.txt containing the single line [code=119888#!198; ttps://egrul.nalog.ru/]:

setlocal enabledelayedexpansion
FOR /F "delims=" %c IN (C:\Users\184863\Desktop\mydata.txt) DO (echo %c  1>>temp_data.txt )
(echo [code=119888#!198; ttps://egrul.nalog.ru/]  1>>temp_data.txt )
endlocal

The trailing space after >>temp_data.txt is now after preprocessing the entire FOR command line with the command block containing only a single command left to  1>>temp_data.txt. When FOR executes the ECHO command line, the trailing space being now an additional space between line read from mydata.txt and  1>>temp_data.txt is also output by ECHO.

It should be always taken into account what is really executed by Windows command interpreter after preprocessing/parsing a command line and not what is written in the batch file.

Furthermore delayed environment variable expansion is enabled which results in line read from the file referenced with %%c being processed by Windows command interpreter for !VariableName! before executing the ECHO command. Everything between two exclamation marks in line is interpreted as variable name and therefore replaced by value of the referenced variable respectively nothing if there is no such environment variable. A single (remaining) exclamation mark is simply removed by Windows command interpreter during this additional processing of the line before ECHO execution.

Solution 1:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "usebackq delims=" %%I in ("%USERPROFILE%\Desktop\mydata.txt") do >>temp_data.txt echo(%%I
endlocal

Delayed environment variable expansion is explicitly disabled in this batch code to interpret exclamation marks always as literal characters.

There is used ( instead of a space character between the command echo and the loop variable reference %%I to output a line starting with /? correct instead of the usage help of command ECHO as it would happen on using echo %%I and a line read from the text file mydata.txt starts with /? after 0 or more leading spaces/tabs.

The text file with the line(s) to read is specified using predefined Windows environment variable USERPROFILE enclosed in double quotes to work on any Windows computer. The double quotes require the option usebackq to get the file name string with path interpreted as text file name from which to read lines.

As a line perhaps ends with a number in range 0 to 9 it is not good to use:

echo %%c>>temp_data.txt

It is better to specify the redirection operator at beginning of the ECHO command line and specify next the echo %%c with no trailing space. Please read the Microsoft documentation about Using command redirection operator for more information.

Please note that FOR ignores empty lines and also all lines starting with a semicolon with the used options. ; is the default for option eol (end of line) which is not explicitly specified in this batch file.

On running this small batch file with @echo off modified to @echo ON from within a command prompt window instead of double clicking on it, it can be seen what Windows command interpreter really executes:

for /F "usebackq delims=" %I in ("C:\Users\184863\Desktop\mydata.txt") do echo %I 1>>temp_data.txt
echo [code=119888#!198; ttps://egrul.nalog.ru/] 1>>temp_data.txt

So it can be seen which command line is finally executed by Windows command interpreter after preprocessing each command line of the batch file before execution. >> was replaced by  1>> (note inserted space at beginning) and the redirection at beginning was moved to end of ECHO command line.

Another solution is enclosing the command ECHO in round brackets to form a command block and redirect the output of this command block with just command ECHO to a file, i.e. use (echo %%c) >>temp_data.txt. The number of spaces after ) do not matter anymore. Therefore (echo %%c)>> temp_data.txt with a space after redirection operator >> and a trailing space at line end results in same text in file temp_data.txt as on using >>temp_data.txt echo %%c.

Solution 2:

@echo off
copy /B temp_data.txt+"%USERPROFILE%\Desktop\mydata.txt" temp_data.txt >nul

The COPY command can be use to merge contents of multiple files specified with + operator together into a single file specified last. This feature is used here to append to existing temp_data.txt the lines from mydata.txt on the user´s desktop. The option /B (binary data) is needed to avoid that COPY appends to output file temp_data.txt ^Z which is the substitute control character SUB with hexadecimal code value 1A.

This solution is definitely better than the first one as it does not matter what the file mydata.txt contains.

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.

  • copy /?
  • echo /?
  • endlocal /?
  • for /?
  • setlocal /?
Mofi
  • 46,139
  • 17
  • 80
  • 143
4

You have a terminal space on the line echo %%c>>temp_data.txt (amongst others) which should be deleted. This is typical of the confusion that terminal spaces causes.

Magoo
  • 77,302
  • 8
  • 62
  • 84
  • @Magoo..i removed the space at the end.but one small issue in my file mydata.txt one line like "[code=119888#!198; ttps://egrul.nalog.ru/]" after my copy to temp_data.txt its look like "[code=119888#//egrul.nalog.ru/]". in between "!198; https:" characters removed.what i observed the characters between (! and :) not printing.any clue for this issue. – Munu Oct 27 '17 at 07:30
  • `!varname!` when `delayed expansion` has been invoked refers to the current value of `varname` in the same way as `%varname%` refers to the parse-time value of `varname` in a `code-block`. The code is interpeting the string following `!` as a substring-replacement construct like `!varname:string1=string2!`. Remove the `enabledelayedexpansion` unless you actually *need* it, – Magoo Oct 27 '17 at 07:59
0

This should do the needful, including the need to comment line 100.

One: Don't use delayed expansion when it isn't necessary.
Two: Remove the trailing space in your echo command.

@(
    SETLOCAL
    ECHO OFF
    SET "_File=C:\Users\184863\Desktop\mydata.txt"
    SET "_Count="
    SET "_Comment=Your Special Comment "
)

FOR /F "tokens=* delims=" %%c IN (%_File%) DO (
    SET /A "Count+=1">NUL
    CALL ECHO.[%COUNT%] | FIND "[100]">NUL && (
        ECHO:%_Comment%%~c
    ) || (
        ECHO.%%c
    )
)>>"%~dp0temp_data.txt"

REM Replace the original file with the commented File
MOVE /Y "%~dp0temp_data.txt" "%_File%"

(
    ENDLOCAL
    EXIT /B 0
)
Ben Personick
  • 3,074
  • 1
  • 22
  • 29
  • i think for my requirment i have to use delayed expansion,because i need to count each line using a counter in side for loop,if the line no is 100 i need to add a specific comment.could you have any idea to achive my requirment. – Munu Oct 27 '17 at 14:04
  • @Munu, Accidentally messaged the wrong user, I amended the solution to work for your needs and decided to split it out into a separate sub to make it a little less obfuscated. – Ben Personick Oct 29 '17 at 15:09