I want to add a newline at the end of a file only if it doesn\'t exists, this is to prevent multiple newlines at the end of the file.
I\'m hoping to use sed. Here\'s the
Using Bash only
You can use Command Substitution (remove trailing newlines) with Here Strings (appends newline):
Command Substitution
Command substitution allows the output of a command to replace the command name. There are two
forms:
$(command)
or
`command`
Bash performs the expansion by executing command in a subshell environment and replacing the com-
mand substitution with the standard output of the command, with any trailing newlines deleted.
Embedded newlines are not deleted, but they may be removed during word splitting. The command sub-
stitution $(cat file) can be replaced by the equivalent but faster $(< file).
Here Strings
A variant of here documents, the format is:
[n]<<<word
The word undergoes brace expansion, tilde expansion, parameter and variable expansion, command sub-
stitution, arithmetic expansion, and quote removal. Pathname expansion and word splitting are not
performed. The result is supplied as a single string, with a newline appended, to the command on
its standard input (or file descriptor n if n is specified).
Here's how it works:
cat <<<"$(<inputfile)"
Output to file:
cat <<<"$(<inputfile)" >outputfile
If you need inputfile
and outputfile
to be the same file name, you have a couple options - use sponge
command, save to temporary variable with more command substitution, or save to temporary file.
Using Sed
Others have suggested using
sed '$a\' inputfile
which appends nothing to the last line. This is fine, but I think
sed '$q' inputfile
is a bit clearer, because it quits on the last line. Or you can do
sed -n 'p'
which uses -n
to suppress output, but prints it back out with p
.
In any of these cases, sed
will fix up the line and add a newline, at least for GNU and BSD sed. However, I'm not sure if this functionality is defined by POSIX. A version of sed
might just skip your line without a newline since a line is defined as
A sequence of zero or more non- characters plus a terminating character.
Using awk :
awk '/^$/{f=1}END{ if (!f) {print "\r"}}1' inputfile
Match blank line ^$
(just like you did) and set up a flag. If flag is not set at the end, place newline character.
Note: that \r
is in OS X. Use \n
for other.
tail -c1 file | read -r _ || echo >> file
gets the last character of the file pipes it into read
, which will exit with a nonzero exit code if it encounters EOF before newline (so, if the last character of the file isn't a newline). If read
exits nonzero, then append a newline onto the file using echo
(if read
exits 0, that satisfies the ||
, so the echo
command isn't run).
From http://backreference.org/2010/05/23/sanitizing-files-with-no-trailing-newline/.
GNU:
sed -i '$a\' *.txt
OS X:
sed -i '' '$a\' *.txt
$
addresses the last line. a\
is the append function.
sed -i '' -n p *.txt
-n
disables printing and p
prints the pattern space. p
adds a missing newline in OS X's sed but not in GNU sed, so this doesn't work with GNU sed.
awk 1
1
can be replaced with anything that evaluates to true. Modifying a file in place:
{ rm file;awk 1 >file; }<file
[[ $(tail -c1 file) && -f file ]]&&echo ''>>file
Trailing newlines are removed from the result of the command substitution, so $(tail -c1 file)
is empty only if file
ends with a linefeed or is empty. -f file
is false if file
is empty. [[ $x ]]
is equivalent to [[ -n $x ]]
in bash.
I solved this task by using dos2unix
(or counterparts) with the --newline
flag. The advantage is that these tools detect binary files on their own. I like the solution with tail -c1
but filtering binary files beforehand has been really slow for me.
dos2unix --newline my_file.txt
Eventually I wrote a script that searched my project directory, converted all files to LF
(dos2unix
) except *.cmd
files (CRLF
, unix2dos
) and used the flag to get the newlines right with one call.
Rather than processing the whole file with see just to add a newline at the end, just check the last character and if it's not a newline, append one. Testing for newline is slightly interesting, since the shell will generally trim them from the end of strings, so I append "x" to protect it:
if [ "$(tail -c1 "$inputfile"; echo x)" != $'\nx' ]; then
echo "" >>"$inputfile"
fi
Note that this will append newline to empty files, which might not be what you want. If you want to leave empty files alone, add another test:
if [ -s "$inputfile" ] && [ "$(tail -c1 "$inputfile"; echo x)" != $'\nx' ]; then
echo "" >>"$inputfile"
fi