I have a Git project that contains a lot of files with no trailing newline. I want to add trailing newlines without adding superfluous newlines. How can I do this?
Asked
Active
Viewed 61 times
1
-
Does this answer your question? [Add a newline only if it doesn't exist](https://stackoverflow.com/questions/10082204/add-a-newline-only-if-it-doesnt-exist) – tripleee Nov 09 '22 at 14:25
-
That question is informative, but addresses the case of only one file. – Zaz Nov 10 '22 at 02:04
-
Trivially, add [Execute command on all files in a directory](https://stackoverflow.com/questions/10523415/execute-command-on-all-files-in-a-directory) – tripleee Nov 10 '22 at 05:07
1 Answers
2
I found this surprisingly tricky to do using the tools I would usually use (grep
, sed
), but an elegant solution does exist using standard shell commands:
tail -c 1 file.txt | read || echo >> file.txt
tail
Outputs the last byte of fileread
Reads a line into a variable. With no variable specified, does nothing, but if an EOF occurs before a newline, exits with code 1.echo
Runs only if read fails (i.e. if the last character was not a newline), and appends a newline tofile.txt
To find the files we want to change you can use find
:
find -not -path "./.git/*" -type f -exec sh -c "grep -Iq . {} && (tail -c 1 {} | read || echo >> {})" \;
-not -path
excludes.git/
, which we don't want to mess with-type f
restricts the search to files-exec sh -c "..."
is required to bundle together commands that include pipesgrep -Iq .
searches for anything (.
) so is a no-op, but exits with code 1 if file is binary{}
marks the position wherefind
will insert the file name
I would advise checking the list of files before running the command. Do this by replacing echo >> {}
with echo {}
:
find -not -path "./.git/*" -type f -exec sh -c "grep -Iq . {} && (tail -c 1 {} | read || echo {})" \;

Zaz
- 46,476
- 14
- 84
- 101