Paul Draper Paul Draper -4 years ago 83
Bash Question

Why isn't [ "$(cat file)" = "$contents" ] true when contents (like the file) ends in a newline?

$ a='a
'
$ echo -n "$a" | md5sum
60b725f10c9c85c70d97880dfe8191b3 -
$ echo -n "$a" > foo
$ cat foo | md5sum
60b725f10c9c85c70d97880dfe8191b3 -
$ [ "$(cat foo)" == "$a" ] || echo false
false


What is happening? Why aren't these equal?

Answer Source

It's because $( ) trims trailing newlines. From the bash reference manual (emphasis added):

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.

You can see this directly by printing the value of $(cat foo):

$ echo "'$a'"
'a
'
$ echo "'$(cat foo)'"
'a'

...note that with $( ), the closing single-quote winds up on the same line as the "a", meaning there's no newline after the "a". Also,

$ [ "$(cat foo)" = "a" ] && echo true || echo false
true

Note that that's comparing against the string "a", which does not contain a newline; not the variable $a, which does contain a newline.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download