Ensure Text Files End with a Newline
From time to time, you may find yourself building up a file comprised of command output and snippets from other files. On these occasions, you will no doubt be using pipes and redirection, and commands such as
Which is all well and good except that you could easily run into trouble if some of the bits and pieces you're cobbling together end with a newline while others don't. For instance,
type will join the last line of a file that doesn't end with a newline with the first line from the next file, forming one long line. Probably not what you want.
Below is a little Batch program that appends a Windows newline sequence (
<CR><LF>) to the end of a text file. Files that already end with a newline will not be modified.
The program accepts a list of one or more filenames from the command line. Wildcards (
*) are permitted (eg,
"*.htm?"). Folders and empty files will be skipped.
@echo off & setlocal enableextensions set /a allfiles=0,valfiles=0,newlines=0 if "%~1"=="" ( echo(specify a file or list of files ^(wildcards permitted^) 1>&2 set /a allfiles=1 & goto end) :loop for %%f in ("%~1") do (set /a allfiles+=1,match=1 if not exist "%%~f" (echo("%%~f" not found 1>&2 & goto break) if exist "%%~f\" (echo("%%~f" is a folder 1>&2 & goto break) set /a valfiles+=1 if not %%~zf==0 (findstr /v $ "%%~f" >nul ^ && (set /a newlines+=1 & echo(>>"%%~f") ) else echo("%%~f" is an empty file 1>&2 ) :break if not defined match (set /a allfiles+=1 echo("%~1" did not match any files in current folder 1>&2) set match= if "%~2" neq "" (shift /1 & goto loop) :end if %valfiles% gtr 0 ^ echo(appended newline to %newlines%/%valfiles% files 1>&2 set /a code=!!(allfiles-valfiles) endlocal & exit /b %code%
The command line parameters are read in one at a time and passed to a simple
for loop. The
for loop is preferred because:
- it can cope with filenames containing Unicode characters
- folder names will be automatically excluded
- if no files in the current folder match a parameter containing wildcards (eg,
"*.tmp"), the body of the loop will not be executed
But filenames containing no wildcard characters will get through. That's why we have to test for the non-existence of every file as well as the existence of a folder by the same name.
Next, we check if the file is empty. If it isn't, we test the file to see whether or not it ends with a newline. This is done using the
findstr /v $ command. Which means output any lines in the file that don't (the
/v switch inverts the command) match the end-of-line marker (
If the test is true (ie, the file doesn't end with a newline), a newline is appended to the end of the file (
And that's essentially it. The rest is for flagging errors and setting the program's exit status (
exit /b %code%). The exit status is stored in the special
%errorlevel% environment variable. A value of
0 means no errors occurred whereas
1 means errors were encountered.
Note that doing the opposite (removing a newline from the end of a file) is a whole other box of crayons and there are no simple pure Batch solutions. It might be the topic of a post in the far distant future 😉
- Q163 of Prof. Timo Salmi's Batch FAQ.
- This alt.msdos.batch.nt thread from June, 2012.
- The tiny trunc utility which will shorten (or lengthen) a file to a specified size in bytes.