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
tailOutputs the last byte of filereadReads a line into a variable. With no variable specified, does nothing, but if an EOF occurs before a newline, exits with code 1.echoRuns 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 -pathexcludes.git/, which we don't want to mess with-type frestricts 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 wherefindwill 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