How to preserve the newline character (\n) when capture output of a command in a variable
Solution 1
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.
Solution 2
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.
Solution 3
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).
Related videos on Youtube
return 0
Updated on September 18, 2022Comments
-
return 0 almost 2 years
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?-
cuonglm over 8 yearsYou mean the leading and trailing newlines was trimmed, or only the trailing ones?
-
Sushant about 8 yearsnitpick:
\n
is Line Feed, not Carriage Return
-
-
cuonglm over 8 yearsNo, adding quotes in the RHS of assignment make no difference. See unix.stackexchange.com/q/178294/38906
-
Mingye Wang over 8 yearsCommand substitution does eat up trailing newlines.
-
Kusalananda over 4 yearsAlso, 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 betweenecho $multiline
andecho "$multiline"
. Also: Why is printf better than echo? -
leaf over 4 yearsHi :-) I would say "the last newlines are trimmed". Am I right ?
-
MrMas about 4 yearsHow I set the variable didn't help but how I used it did which is why I like this answer.
-
nullPainter about 3 yearsYou could avoid the need to remove
x
by using$ output=$(head -- "$file"; echo '')"
(i.e. echo an empty string, will still makeecho
print the newline). -
Faither about 3 yearsRelated: mywiki.wooledge.org/CommandSubstitution (Command substitutions strip all trailing newlines from the output of the command inside them).
-
Robin A. Meade almost 3 years"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