Over at Can you modify text files when committing to subversion? Grant suggested that I block commits instead.
However I don't know how to check a file ends with a newline. How can you detect that the file ends with a newline?
Over at Can you modify text files when committing to subversion? Grant suggested that I block commits instead.
However I don't know how to check a file ends with a newline. How can you detect that the file ends with a newline?
Here is a useful bash function:
function file_ends_with_newline() {
[[ $(tail -c1 "$1" | wc -l) -gt 0 ]]
}
You can use it like:
if ! file_ends_with_newline myfile.txt
then
echo "" >> myfile.txt
fi
# continue with other stuff that assumes myfile.txt ends with a newline
@Konrad: tail does not return an empty line. I made a file that has some text that doesn't end in newline and a file that does. Here is the output from tail:
$ cat test_no_newline.txt
this file doesn't end in newline$
$ cat test_with_newline.txt
this file ends in newline
$
Though I found that tail has get last byte option. So I modified your script to:
#!/bin/sh
c=`tail -c 1 $1`
if [ "$c" != "" ]; then
echo "no newline"
fi
Or even simpler:
#!/bin/sh
test "$(tail -c 1 "$1")" && echo "no newline at eof: '$1'"
But if you want a more robust check:
test "$(tail -c 1 "$1" | wc -l)" -eq 0 && echo "no newline at eof: '$1'"
You could use something like this as your pre-commit script:
#! /usr/bin/perl while (<>) { $last = $_; } if (! ($last =~ m/\n$/)) { print STDERR "File doesn't end with \\n!\n"; exit 1; }
Using only bash
:
x=`tail -n 1 your_textfile`
if [ "$x" == "" ]; then echo "empty line"; fi
(Take care to copy the whitespaces correctly!)
@grom:
tail does not return an empty line
Damn. My test file didn't end on \n
but on \n\n
. Apparently vim
can't create files that don't end on \n
(?). Anyway, as long as the “get last byte” option works, all's well.
Worked for me:
tail -n 1 /path/to/newline_at_end.txt | wc --lines
# according to "man wc" : --lines - print the newline counts
So wc counts number of newline chars, which is good in our case. The oneliner prints either 0 or 1 according to presence of newline at the end of the file.
A complete Bash solution with only tail
command, that also deal correctly with empty files.
#!/bin/bash
# Return 0 if file $1 exists and ending by end of line character,
# else return 1
[[ -s "$1" && -z "$(tail -c 1 "$1")" ]]
-s "$1"
checks if the file is not empty-z "$(tail -c 1 "$1")"
checks if its last (existing) character is end of line character[[...]]
conditional expression is returnedYou can also defined this Bash function to use it in your scripts.
# Return 0 if file $1 exists and ending by end of line character,
# else return 1
check_ending_eol() {
[[ -s "$1" && -z "$(tail -c 1 "$1")" ]]
}
The read
command can not read a line without newline.
if tail -c 1 "$1" | read -r line; then
echo "newline"
fi
Another answer.
if [ $(tail -c 1 "$1" | od -An -b) = 012 ]; then
echo "newline"
fi
I'm coming up with a correction to my own answer.
Below should work in all cases with no failures:
nl=$(printf '\012')
nls=$(wc -l "${target_file}")
lastlinecount=${nls%% *}
lastlinecount=$((lastlinecount+1))
lastline=$(sed ${lastlinecount}' !d' "${target_file}")
if [ "${lastline}" = "${nl}" ]; then
echo "${target_file} ends with a new line!"
else
echo "${target_file} does NOT end with a new line!"
fi
You can get the last character of the file using tail -c 1
.
my_file="/path/to/my/file"
if [[ $(tail -c 1 "$my_file") != "" ]]; then
echo "File doesn't end with a new line: $my_file"
fi