echo and printf¶
Intro¶
Note
For all the examples that follow, set the PS1
prompt to a
simple $␠
(the dollar sign followed by a single whitespace)
unless otherwise noted. E.g:
PS1='\$ '
echo¶
echo and newline¶
$ echo -n
Why does echo -n
still produce a newline and the next prompt is
on a line of its own?
It is not echo
that is producing a newline. Because we first add
a newline by hitting Enter (a.k.a Return) in order to
execute the command, then bash prints nothing (we provided nothing for
echo
to print), the output is a newline from our Enter and
nothing else. The $
prompt is positioned on a line of its own
simply because echo
had nothing to print.
When we do echo -n foo
and hit Enter, we first produce a
newline, then bash prints ‘foo’.
$ echo -n foo<Return>
foo$
Then the prompt $
is positioned immediately after ‘foo’. After
all, we asked echo
NOT to append a newline, so, echo
prints
‘foo’ and the prompt is positioned right after echo
’s output.
How to print ‘-n’?¶
If we just do echo -n
, the -n
is treated as the -n
option
(do not append a newline).
This doesn’t work:
$ echo -- -n
-- -n.
Not what we want… We learned in End Of Options ‘--’ that a anything following
__
should be treated as a normal string operand, and not as an option to the
program. Why then --
is not working here and preventing -n
from
beting treaded an option‽ Because bash’s echo
honors the
specs:
The echo utility shall not recognize the “--” argument in the manner specified by Guideline 10 of XBD Utility Syntax Guidelines; “--” shall be recognized as a string operand.
—echo POSIX spec
We can man ascii
and look for the numeric value of --
:
Excerpt from `man ascii’.
Oct Dec Hex Char
──────────────────────
...
055 45 2D -
...
Then we can use the -e
option for echo
and use the octal or
hexadecimal values to produce -
and just implicitly concatenate both
-
and n
.
$ echo -e '\055'n
-n
$ echo -e '\x2d'n
-n
It has been said that:
“Any fool can make something complicated. It takes a genius to make it simple.”
Therefore:
$ echo -n -; echo n;
Jokes apart, the version with -e
and \x2d
is cool and useful
too. It is nice to have the tools and know how to use them.
Nice question and discussion: When and how was the double-dash (--) introduced as an end of options delimiter in Unix/Linux?
Prefer printf instead of echo¶
The use of echo
is discouraged for several reasons. First, see
echo application usage.
Basically, behaviour differs across implementations making it all but
impossible to use echo
in a reliable and portable way.
Also, observe the output of these commands:
$ var=-e
$ echo "$var"
Nothing is printed. 😮
$ arr=(-e -n -en -ne)
$ echo "${arr[@]}"
Same problem… But we are fine with printf
:
$ var=-e
$ printf '%s\n' "$var"
-e
$ arr=(-e -n -en -ne)
$ printf '%s\n' "${arr[@]}"
-e
-n
-en
-ne
However, these work with echo
:
$ var=-e
$ echo "hello $var"
hello -e
$ arr=(-e -n -en -ne)
$ printf 'hello %s\n' "${arr[@]}"
hello -e
hello -n
hello -en
hello -ne
As do these:
$ echo " $var"
-e
$ printf ' %s\n' "${arr[@]}"
-e
-n
-en
-ne
In bash’s echo
at least, we can print those option-like
parameters as long as there is something before them. Even a
whitespace before them causes it to work. But do note that the space
is preserved in the output.
Well, the options are there, and echo
can still be used for
certain things, but care must be taken.
printf¶
Contrary to echo
, printf
does not add a newline by default.
$ printf '%s' hello
hello$
$ printf '%s\n' hello
hello
$
Format operand reutilization¶
Another thing to consider is that the format operand (%s
,
%d
, etc.) is reused until all argument operands are consumed:
“The format operand shall be reused as often as necessary to satisfy the argument operands.”
That explains why even with a single %s
, the next line prints all
argument operands (instead of just the first one):
$ printf '%s\n' may the force
may
the
force
$ words=(be with you)
$ printf '%s\n' "${words[@]}"
be
with
you