19

As a simple example, I have a bunch of source code files. I want to store the "head" command output to a variable for all these files.

I tried:

output=$(head $file)

but what happened is that this automatically trimmed all \n characters when storing the output to a variable.

How do I store the command output as is without removing \n characters?

2
  • 1
    You mean the leading and trailing newlines was trimmed, or only the trailing ones?
    – cuonglm
    Commented Dec 9, 2015 at 2:14
  • 1
    nitpick: \n is Line Feed, not Carriage Return Commented Apr 14, 2016 at 21:07

3 Answers 3

16

It is a known flaw of "command expansion" $(...) or `...` that the last newline is trimmed.

If that is your case:

$ output="$(head -- "$file"; echo x)"     ### capture the text with an x added.
$ output="${output%?}"                    ### remove the last character (the x).

Will correct the value of output.

5
  • 5
    Also, outputting the value with e.g. echo would never preserve the internal newlines if the variable expansion wasn't quoted. See e.g. the difference between echo $multiline and echo "$multiline". Also: Why is printf better than echo?
    – Kusalananda
    Commented Nov 26, 2019 at 18:33
  • 2
    Hi :-) I would say "the last newlines are trimmed". Am I right ?
    – leaf
    Commented Jan 26, 2020 at 9:51
  • You could avoid the need to remove x by using $ output=$(head -- "$file"; echo '')" (i.e. echo an empty string, will still make echo print the newline). Commented May 12, 2021 at 2:58
  • 1
    Related: mywiki.wooledge.org/CommandSubstitution (Command substitutions strip all trailing newlines from the output of the command inside them).
    – Artfaith
    Commented Jun 5, 2021 at 22:51
  • 1
    "the last newline is trimmed" incorrectly implies that command substitution trims at most one trailing newline, when, in reality, "sequences of one or more <newline> characters at the end of the substitution" are removed. – POSIX Commented Jul 17, 2021 at 20:25
13

output=$(head $file) keeps embedded newlines in the value of output, and trims all trailing newlines.

It's how you reference the variable that makes the difference.

Placing the variable reference within double quotes, for example:

echo "$output"

prints the embedded newlines, but not the trailing newlines, which were deleted by the command expansion $(...).

This works because the shell interprets only dollar sign, command expansion (back quotes and $(...)), and back slashes within double quotes; the shell does not interpret whitespace (including newlines) as field separators when inside double quotes.

4
  • 1
    No, adding quotes in the RHS of assignment make no difference. See unix.stackexchange.com/q/178294/38906
    – cuonglm
    Commented Dec 9, 2015 at 2:15
  • 2
    Command substitution does eat up trailing newlines. Commented Dec 9, 2015 at 3:12
  • How I set the variable didn't help but how I used it did which is why I like this answer.
    – MrMas
    Commented Apr 20, 2020 at 17:46
  • Re: "trailing newlines, which were deleted by the command expansion $(...)" is this a bug or feature?
    – pmor
    Commented May 23 at 11:34
4

To also preserve the exit status:

output=$(head < "$file"; r=$?; echo /; exit "$r")
exit_status=$?
output=${output%/}

Note that using / is safer than x as there are some character sets used by some locales where the encoding of some characters end in the encoding of x (while the encoding of / would generally not be found in other characters as that would make path lookup problematic for instance).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .