I'm trying to get the output of env
in a shell variable and print it.
#!/bin/sh
ENV_BEFORE=$(env)
printf $ENV_BEFORE
As a result a single variable from the env
output gets printed.
When using echo
instead of printf
all the output is printed, however without the newlines.
What am I missing here?
Best Answer
The problem is that you're not quoting the
$ENV
variable. As explained inman bash
:So, enclosing a sequence like
\n
in double quotes preserves its meaning. This is why, when not quoted,\n
is just a normaln
:While, when quoted:
An unquoted variable in bash invokes the split+glob operator. This means that the variable is split on whitespace (or whatever the special variable
$IFS
has been set to) and each resulting word is used as a glob (it will expand to match any matching file names). Your problem is with the "split" part of this.To illustrate, let's take a simpler multiline variable:
Now, using the shell's
set -x
debug feature, you can see exactly what's going on:As you can see above,
echo $var
(unquoted) subjects$var
to split+glob so it results in two separate strings,foo
andbar
. The newline was eaten by th split+glob. When the variable was quoted, it wasn't subjected to split+glob, the newline was kept and, because it is quoted, is also interpreted correctly ad printed out.The next problem is that
printf
is not likeecho
. It doesn't just print anything you give it, it expects a format string. For exampleprintf "color:%s" "green"
will printcolor:green
because the%s
will be replaced withgreen
.It also ignores any input that can't fit into the format string it was given. So, if you run
printf foo bar
,printf
will treatfoo
as its format string andbar
as the variable it is supposed to format with it. Since there is no%s
or equivalent to be replaced bybar
,bar
is ignored andfoo
alone is printed:That's what happened when you ran
printf $ENV_BEFORE
. Because the variable wasn't quoted, the split glob effectively replaced newlines with spaces, andprintf
only printed the first "word" it saw.To do it correctly, use format strings, and always quote your variables: