Is there a Windows command to convert line endings of a file?
We have a test.bat
which we need to run to start our server. We use Perforce and we need to have unix line endings in our workspace. For some reason, we are not allowed to change line endings to Windows in our workspaces. However, the server runs on Windows.
Everytime I have to run the bat file, I open it in Notepad++ and choose Edit→EOL conversion→Windows. Is there a way to automate this so that we won't need to manually change the line endings everytime we sync with Perforce?
Thanks in advance.
This can actually be done very easily using the more
command which is included in Windows NT and later. To convert input_filename
which contains UNIX EOL (End Of Line) \n
to output_filename
which contains Windows EOL \r\n
, just do this:
TYPE input_filename | MORE /P > output_filename
The more
command has additional formatting options that you may not be aware of. Run more/?
to learn what else more
can do.
Use unix2dos utility. You can download binaries here.
at
job, which filters all files in some folder you put your batch files in. It all depends on what do you mean by automation.
I was dealing with CRLF
issues so I decided to build really simple tool for conversion (in NodeJS):
So if you have NodeJS with npm installed you can try it:
npm i -g eol-converter-cli
eolConverter crlf "**/*.{txt,js,java,etc}"
Path might be configured dynamically by using Glob regex (same regex as in shell).
So if you can use NodeJS, it's really simple and you can integrate this command to convert whole workspace to desired line endings.
You can do this without additional tools in VBScript:
Do Until WScript.StdIn.AtEndOfStream
WScript.StdOut.WriteLine WScript.StdIn.ReadLine
Loop
Put the above lines in a file unix2dos.vbs
and run it like this:
cscript //NoLogo unix2dos.vbs <C:\path\to\input.txt >C:\path\to\output.txt
or like this:
type C:\path\to\input.txt | cscript //NoLogo unix2dos.vbs >C:\path\to\output.txt
You can also do it in PowerShell:
(Get-Content "C:\path\to\input.txt") -replace "`n", "`r`n" |
Set-Content "C:\path\to\output.txt"
which could be further simplified to this:
(Get-Content "C:\path\to\input.txt") | Set-Content "C:\path\to\output.txt"
The above statement works without an explicit replacement, because Get-Content
implicitly splits input files at any kind of linebreak (CR, LF, and CR-LF), and Set-Content
joins the input array with Windows linebreaks (CR-LF) before writing it to a file.
Get-Content
make that possible). As for "in-place" editing in general: see here.
Windows' MORE is not reliable, it destroys TABs inevitably and adds lines.
unix2dos is part also of MinGW/MSYS, Cygutils, GnuWin32 and other unix binary port collections - and may already be installed.
When python is there, this one-liner converts any line endings to current platform - on any platform:
TYPE UNIXFILE.EXT | python -c "import sys; sys.stdout.write(sys.stdin.read())" > MYPLATFILE.EXT
or
python -c "import sys; sys.stdout.write(open(sys.argv[1]).read())" UNIXFILE.EXT > MYPLATFILE.EXT
Or put the one-liner into a .bat / shell script and on the PATH according to your platform:
@REM This is any2here.bat
python -c "import sys; sys.stdout.write(open(sys.argv[1]).read())" %1
and use that tool like
any2here UNIXFILE.EXT > MYPLATFILE.EXT
Building on TampaHaze's and MD XF's helpful answers.
This will change all .txt files in place in the current directory from from LF to CRLF in Command Prompt
for /f "delims=" %f in ('dir /b "*.txt"') do ( type "%f" | more /p > "%f.1" & move "%f.1" "%f" )
If you don't want to verify every single change
move
To
move /y
To include subdirectories change
dir /b
To
dir /b /s
To do all this in a batch file including subdirectories without prompting for .txt
files use below
@echo off
setlocal enabledelayedexpansion
for /f "delims=" %%f in ('dir /s /b "*.txt"') do (
type "%%f" | more /p > "%%f.1"
move /y "%%f.1" "%%f" > nul
@echo Changing LF-^>CRLF in File %%f
)
echo.
pause
try this:
(for /f "delims=" %i in (file.unix) do @echo %i)>file.dos
Session protocol:
C:\TEST>xxd -g1 file.unix 0000000: 36 31 36 38 39 36 32 39 33 30 38 31 30 38 36 35 6168962930810865 0000010: 0a 34 38 36 38 39 37 34 36 33 32 36 31 38 31 39 .486897463261819 0000020: 37 0a 37 32 30 30 31 33 37 33 39 31 39 32 38 35 7.72001373919285 0000030: 34 37 0a 35 30 32 32 38 31 35 37 33 32 30 32 30 47.5022815732020 0000040: 35 32 34 0a 524. C:\TEST>(for /f "delims=" %i in (file.unix) do @echo %i)>file.dos C:\TEST>xxd -g1 file.dos 0000000: 36 31 36 38 39 36 32 39 33 30 38 31 30 38 36 35 6168962930810865 0000010: 0d 0a 34 38 36 38 39 37 34 36 33 32 36 31 38 31 ..48689746326181 0000020: 39 37 0d 0a 37 32 30 30 31 33 37 33 39 31 39 32 97..720013739192 0000030: 38 35 34 37 0d 0a 35 30 32 32 38 31 35 37 33 32 8547..5022815732 0000040: 30 32 30 35 32 34 0d 0a 020524..
My contribution for this, converting several files in a folder: for %%z in (*.txt) do (for /f "delims=" %%i in (%%z) do @echo %%i)>%%z.tmp
If you have bash (e.g. git bash), you can use the following script to convert from unix2dos:
ex filename.ext <<EOF
:set fileformat=dos
:wq
EOF
similarly, to convert from dos2unix:
ex filename.ext <<EOF
:set fileformat=unix
:wq
EOF
You could create a simple batch script to do this for you:
TYPE %1 | MORE /P >%1.1
MOVE %1.1 %1
Then run <batch script name> <FILE>
and <FILE>
will be instantly converted to DOS line endings.
I cloned my git project using the git bash
on windows
. All the files then had LF
endings. Our repository has CRLF
endings as default.
I deleted the project, and then cloned it again using the Windows Command Prompt
. The CRLF
endings were intact then. In my case, if I had changed the endings for the project, then it would've resulted in a huge commit and would've caused trouble for my teammates. So, did it this way. Hope this helps somebody.
Here's a simple unix2dos.bat file that preserves blank lines and exclamation points:
@echo off
setlocal DisableDelayedExpansion
for /f "tokens=1,* delims=:" %%k in ('findstr /n "^" %1') do echo.%%l
The output goes to standard out, so redirect unix2dos.bat output to a file if so desired.
It avoids the pitfalls of other previously proposed for /f batch loop solutions by:
1) Working with delayed expansion off, to avoid eating up exclamation marks.
2) Using the for /f tokenizer itself to remove the line number from the findstr /n
output lines.
(Using findstr /n is necessary to also get blank lines: They would be dropped if for /f read directly from the input file.)
But, as Jeb pointed out in a comment below, the above solution has one drawback the others don't: It drops colons at the beginning of lines.
So 2020-04-06 update just for fun, here's another 1-liner based on findstr.exe, that seems to work fine without the above drawbacks:
@echo off
setlocal DisableDelayedExpansion
for /f "tokens=* delims=0123456789" %%l in ('findstr /n "^" %1') do echo%%l
The additional tricks are:
3) Use digits 0-9 as delimiters, so that tokens=*
skips the initial line number.
4) Use the colon, inserted by findstr /n
after the line number, as the token separator after the echo command.
I'll leave it to Jeb to explain if there are corner cases where echo:something
might fail :-)
All I can say is that this last version successfully restored line endings on my huge batch library, so exceptions, if any, must be quite rare!
:
from line beginnings. That destroys all batch functions. Btw. Test to convert a file with a line like \..\..\windows\system32\calc.exe
. To solve this look at this explanation
..\..\..\..\..\windows\system32\calc.exe
. The only safe ECHO form is the echo(
. A one liner could be possible, but I suppose it's tricky
Based on Endoro's answer but to keep the blanks, try this:
@echo off
setlocal enabledelayedexpansion
(for /f "tokens=* delims=:" %%i in ('findstr /n "^" file.unix') do (
set line=%%i
set line=!line:*:=!
echo(!line!
))>file.dos
Late to the party, but there is still no correct answer using a FOR /F
loop.
(But you don't need a FOR loop at all, the solution from @TampaHaze works too and is much simpler)
The answer from @IR relevant has some drawbacks.
It drops the exclamation marks and can also drop carets.
@echo off
(
setlocal Disabledelayedexpansion
for /f "tokens=* delims=" %%L in ('findstr /n "^" "%~1"') do (
set "line=%%L"
setlocal enabledelayedexpansion
set "line=!line:*:=!"
(echo(!line!)
endlocal
)
) > file.dos
The trick is to use findstr /n
to prefix each line with <line number>:
, this avoids skipping of empty lines or lines beginning with ;
.
To remove the <number>:
the FOR "tokens=1,* delims=:"
option can't be used, because this would remove all leading colons in a line, too.
Therefore the line number is removed by set "line=!line:*:=!"
, this requires EnableDelayedExpansion.
But with EnableDelayedExpansion
the line set "line=%%L"
would drop all exclamation marks and also carets (only when exclams are in the line).
That's why I disable the delayed expansion before and only enable it for the two lines, where it is required.
The (echo(!line!)
looks strange, but has the advantage, that echo(
can display any content in !line!
and the outer parenthesis avoids accidentials whitespaces at the line end.
For convert UNIX(LF) to Windows(CR-LF) use next command on your windows terminal.
type file.txt > new_file.txt
I'm taking an AWS course and have frequently had to copy from text boxes in the AWS web forms to Windows Notepad. So I get the LF-delimited text only on my clipboard. I accidentally discovered that pasting it into my Delphi editor, and then hitting Ctrl+K+W will write the text to a file with CR+LF delimiters. (I'll bet many other IDE editors would do the same).
Inserting Carriage Returns to a Text File
@echo off
set SourceFile=%1 rem c:\test\test.txt
set TargetFile=%2 rem c:\test\out.txt
if exist "%TargetFile%" del "%TargetFile%"
for /F "delims=" %%a in ('type "%SourceFile%"') do call :Sub %%a
rem notepad "%TargetFile%"
goto :eof
:Sub
echo %1 >> "%TargetFile%"
if "%2"=="" goto :eof
shift
goto sub
(for /f "tokens=*" %%a in (%~1) do @echo.%%a)>"%~2"
.
set TargetFile=%2 rem c:\test\out.txt
also needs improvement. And, btw, your "tokens=*"
also.
Success story sharing
more /P <input_file >output_file