9

This question already has an answer here:

Contents of file.txt (no weirdness, text file as defined by POSIX)

iguana
gecko
anole

Sample script:

#!/bin/sh

string="$(cat file.txt)"

printf '%s' "$string"

Sample output:

[coolguy@somemachine ~]$ ./script.sh
iguana
gecko
anole[coolguy@somemachine ~]$

What happened to the last newline? Why are all are newlines except the last one preserved? It seems like we shouldn't have to use echo to add a newline if there should already be one there.

marked as duplicate by Barmar, schily, roaima, Jeff Schaller, Jesse_b Jun 7 '18 at 13:52

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 3
    @Jesse_b - according to POSIX "a text file, contains characters organized into one or more lines" and "a line is a sequence of zero or more non-newline characters plus a terminating newline character." – don_crissti May 30 '18 at 21:08
  • @dave_thompson_085 Should I delete it? – Harold Fischer May 31 '18 at 0:42
  • 1
    Might be worth mentioning that, for the same design rationale, here-string redirections add a newline at the end of the string provided, like in cat <<< foo. – JoL May 31 '18 at 4:46
25

It's not the printing, it's the command substitution that does that. It's defined to do that. From the POSIX description:

The shell shall expand the command substitution by executing command in a subshell environment and replacing the command substitution with the standard output of the command, removing sequences of one or more {newline} characters at the end of the substitution.

Note that it removes all trailing newlines, not just one.

In a somewhat common case, you'd use command substitution to capture a one-line output, say osrev=$(uname -r). The utilities usually print a trailing newline, for user convenience on the command line. But in a shell script, you might want to use that string as part of another one, say a filename: filename=blahblah-$osrev.dat. And in that case, the trailing newline would only be a nuisance.

And of course, a plain echo will add a final newline in any case.


If you want the contents of the file as-is in the variable, then the common workaround is to add an extra character in the command substitution, and remove that later:

printf "foo\nbar\n\n" > file
string=$(cat file; echo x)
string=${string%x}
printf '%q\n' "$string"

that outputs $'foo\nbar\n\n', showing both trailing newlines present.


Depending on what you intend to do with the data, there may be other ways. E.g. a while read loop, or Bash's mapfile, if you happen to want to process the file line-by-line.

  • This question has been marked as a duplicate. Is it good practice to delete a question after it has been marked as such? – Harold Fischer Jun 18 '18 at 20:16
  • @HaroldFischer, there's a whole bunch of questions marked duplicates on the site, so no, not really. And I don't think you even could delete it, since there's an upvoted answer. See deleted-questions. – ilkkachu Jun 18 '18 at 20:45

Not the answer you're looking for? Browse other questions tagged or ask your own question.