0

I want to nest a for loop inside a batch file to delete carriage return. I tried it like you can see below but it does not work.

@echo off
setLocal EnableDelayedExpansion

for /f "tokens=* delims= " %%a in (Listfile.txt) do (
    set /a N+=1
    set v!N!=%%a
)

for /l %%i in (1, 1, %N%) do (
    echo !v%%i!
    for /r "tokens=* delims=" %%i in (windows.cpp) do (
        echo %%i >> Linux11.cpp
    )
)
pause

Here I want to check with windows.cpp. If its working I like to change windows .cpp with !v%%i!

aschipfl
  • 33,626
  • 12
  • 54
  • 99
user375191
  • 123
  • 2
  • 4
  • 7
  • The last (inner) for syntax is wrong: there is the switch `/r` stated but there is an option string provided (`"tokens=* delims="`) as expected if using switch `/f`... – aschipfl Nov 27 '15 at 00:12
  • To convert end-of-line markers (or line-breaks) between platforms you may want to check out [this answer](https://stackoverflow.com/q/19912941/59278398#59278398)... – aschipfl Apr 08 '20 at 16:17

3 Answers3

7

You cannot do this in a batch file. You have no way of addressing or writing arbitrary characters. Every tool on Windows normally makes sure to output Windows line breaks (i.e. CR+LF). Some can read Unix-style line breaks just fine, which is why you can easily convert from them. But to them isn't possible.

Also as a word of caution: Source code files often contain blank lines (at least mine do) that are for readability. for /f skips empty lines which is why you're mangling the files for your human readers there. Please don't do that.

As for your question: When nesting two loops you have to make sure that they don't use the same loop variable. Show me a language where code like you wrote actually works.

Something like

for /l %%i in (1, 1, %N%) do ( 
  echo !v%%i! 
  for /f "tokens=* delims=" %%l in ("!v%%i!") do (   
    rem do whatever you want to do with the lines
  )
)

should probably work better (you missed the final closing parenthesis as well). Thing to remember: If you want to use a certain variable instead of a fixed file name it surely helps replacing that fixed file name by that variable.

aschipfl
  • 33,626
  • 12
  • 54
  • 99
Joey
  • 344,408
  • 85
  • 689
  • 683
  • here in echo %%i >> Linux11.cpp i am getting the file name , its not copying the content in that *.cpp files in Listfile.txt – user375191 Jun 29 '10 at 11:00
  • echo just writes a string to the screen ... what makes you think that it would actually do anything with a file's contents? – Joey Jun 29 '10 at 12:27
1

It would be probably easiest to use some unix2dos/dos2unix converter to do that or some win32 flavor of sed.

0

The intrinsic issue of your code is already addressed by another answer, hence I am going to focus on the main task you are trying to accomplish, namely converting DOS/Windows-style end-of-line markers (or line-breaks) to Unix-style ones.

Doing this is very tricky in a batch file, but give the following script a try. Supposing it is called convert.bat, and the original text file is named convert.txt, run the script using the following command line:

convert.bat "convert.txt" LF

The name of the returned file will get the original file name with _converted_EOL appended. The second argument LF specifies Unix-style line-breaks; omitting it will return DOS/Windows-style ones.

So here is the code:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem check whether or not an existing file is given as the first argument
>&2 (
    if "%~1"=="" (
        echo No file specified.
        exit /B 2
    ) else if not exist "%~1" (
        echo File "%~1" not found.
        exit /B 1
    )
)

rem get carriage-return character
for /F %%A in ('copy /Z "%~0" nul') do set "CR=%%A"

rem get line-feed character (the two empty lines afterwards are mandatory!)
(set ^"LF=^
%= blank line =%
^")

rem check which line-break is given by the second argument
rem (`CR` - carriage return (Mac); `LF` - line feed (Unix);
rem  anything else or nothing - CR+LF (Windows, default))
setlocal EnableDelayedexpansion
set "BR=!CR!!LF!"
if /I "%~2"=="CR" set "BR=!CR!" & (>&2 echo CR not supported.) & exit /B 3
if /I "%~2"=="LF" set "BR=!LF!"

rem convert line-breaks; append `_converted_EOL` to file name
setlocal DisableDelayedExpansion
> "%~n1_converted_EOL%~x1" (
    for /F delims^=^ eol^= %%L in ('
        findstr /N /R "^" "%~1"
    ') do (
        set "LINE=%%L"
        rem firstly, precede every line with a dummy character (`:`) and
        rem append the specified line-break in order to avoid the loss of
        rem leading white-spaces or trouble with leading equal-to signs,
        rem all caused by `set /P`, which is needed here to return the
        rem line without a trailing DOS/Windows-style line-break (opposed
        rem to `echo`); then, let `pause` strip off that character;
        rem lastly, let `findstr` return the remainder;
        rem (the `rem` suffix is just there to fix syntax highlighting)
        cmd /V /C ^< nul set /P #="!LINE:*:=:!!BR!" | (> nul pause & findstr "^") & rem/ "^"
    )
)
endlocal
endlocal

endlocal
exit /B

The following restrictions apply:

  • no line must be longer than about 8190 characters (this is a general limitation of batch files);
  • the file must not contain any null-bytes (well, a normal text file should not hold such, but Unicode-encoded do);
  • the last line of the returned file will always be terminated by a line-break, even if the respective original line is not;

And here is another solution for line-break conversions: Convert all CR to CRLF in text file using CMD

aschipfl
  • 33,626
  • 12
  • 54
  • 99