1

In Linux - check if there is an empty line at the end of a file, some posts make use of [[ ]] and == to compare characters.

I would like to write a one-line command for detecting if there's no newline at EOF, and I came across this little problem.

In the output of echo, there's \n at the end.

$ echo echo | od -c           
0000000   e   c   h   o  \n
0000005
$ echo -n echo | od -c           
0000000   e   c   h   o
0000004

If I put [[ ]] and == together, then I don't get the expected output.

$ [[ `echo echo | tail -c1` == "\n" ]] && echo true
$ [[ `echo echo | tail -c1` != "\n" ]] && echo true
true
$ [[ `echo -n echo | tail -c1` != "\n" ]] && echo true
true

As shown by od -c, the output of echo echo | tail -c1 is \n, and [[ "\n" == "\n" ]] && true would return true, so I expect the first command gives true. However, why is it evaluated to empty string?

Thanks for reading!

2 Answers2

2

As it is clearly stated in the Bash Reference Manual:

Bash performs the expansion by executing command in a subshell environment and replacing the command substitution with the standard output of the command, with any trailing newlines deleted.

Turn on the -x flag to see what happens clearly:

$ set -x
$ [[ `echo echo | tail -c 1` == '\n' ]]
++ tail -c 1
++ echo echo
+ [[ '' == \\\n ]]
$
$ echo "$(echo)"
++ echo
+ echo ''

And as a sidenote, even if trailing newlines weren't trimmed your comparison wouldn't return true, because '\n' is not a line feed, but literally a backslash followed by the letter n. You should use $'\n' to get an actual line feed.

oguz ismail
  • 1
  • 16
  • 47
  • 69
1

As for a solution, you can use the following:

$ printf 'test\n' | perl -0777ne'exit(/\n\z/?0:1)' || echo "Missing line feed" >&2

$ printf 'test'   | perl -0777ne'exit(/\n\z/?0:1)' || echo "Missing line feed" >&2
Missing line feed

or

$ printf 'test\n' | perl -0777ne'die("Missing line feed\n") if !/\n\z/'

$ printf 'test'   | perl -0777ne'die("Missing line feed\n") if !/\n\z/'
Missing line feed
ikegami
  • 367,544
  • 15
  • 269
  • 518