Daniel Veillard wrote:
On Wed, Apr 14, 2010 at 01:28:54PM +0200, Jim Meyering wrote:
> echo -e is not portable.
> This is the sole remaining use in all of libvirt.
>
> >From a58cf340b5ebbca2157f43c6f23d4d6f56b848c7 Mon Sep 17 00:00:00 2001
> From: Jim Meyering <meyering(a)redhat.com>
> Date: Wed, 14 Apr 2010 13:25:46 +0200
> Subject: [PATCH] schematestutils.sh: improve shell portability: avoid "echo
-e"
>
> * tests/schematestutils.sh: Use printf rather than echo -e.
> ---
> tests/schematestutils.sh | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/tests/schematestutils.sh b/tests/schematestutils.sh
> index f172857..f2b3b50 100644
> --- a/tests/schematestutils.sh
> +++ b/tests/schematestutils.sh
> @@ -22,7 +22,7 @@ do
>
> test_result $n $(basename $(dirname $xml))"/"$(basename $xml) $ret
> if test "$verbose" = "1" && test $ret != 0 ; then
> - echo -e "$cmd\n$result"
> + printf '%s\n' "$cmd" "$result"
> fi
> if test "$ret" != 0 ; then
> f=`expr $f + 1`
I fail to see how printf(1) is any more portable than echo which
is usually from the shell itself. Sounds to me that
echo "$cmd" ; echo "$result"
does what we want directly or am I mistaken ?
printf is most definitely more portable than "echo -e".
Note that printf has been a shell built-in in just about every
shell in common use for at least 10 years.
Documentation everywhere has been telling developers to prefer
"printf" over "echo-with-any-options" for nearly 20 years.
Here's an excerpt from "info coreutils echo":
POSIX does not require support for any options, and says that the
behavior of `echo' is implementation-defined if any STRING contains a
backslash or if the first argument is `-n'. Portable programs can use
the `printf' command if they need to omit trailing newlines or output
control characters or backslashes. *Note printf invocation::.
While my objection was to "echo -e", plain 'echo "$var"'
(where $var may be arbitrary) is not terribly reliable.
There are plenty of caveats when using plain "echo".
I.e., the first argument must not start with a "-".
Using printf the way I do above, even if $cmd or $value starts with "-"
or contains backslashes, it will be faithfully reproduced.
However, if you use your pair of "echo" commands
and some $result starts with "-", you'll get misleading output.
Here's the section on "echo" in autoconf's "Limitations of
Builtins" section:
`echo'
The simple `echo' is probably the most surprising source of
portability troubles. It is not possible to use `echo' portably
unless both options and escape sequences are omitted. Don't
expect any option.
Do not use backslashes in the arguments, as there is no consensus
on their handling. For `echo '\n' | wc -l', the `sh' of Solaris
outputs 2, but Bash and Zsh (in `sh' emulation mode) output 1.
The problem is truly `echo': all the shells understand `'\n'' as
the string composed of a backslash and an `n'. Within a command
substitution, `echo 'string\c'' will mess up the internal state of
ksh88 on AIX 6.1 so that it will print the first character `s'
only, followed by a newline, and then entirely drop the output of
the next echo in a command substitution.
Because of these problems, do not pass a string containing
arbitrary characters to `echo'. For example, `echo "$foo"' is
safe
only if you know that FOO's value cannot contain backslashes and
cannot start with `-'.
If this may not be true, `printf' is in general safer and easier
to use than `echo' and `echo -n'. Thus, scripts where portability
is not a major concern should use `printf '%s\n'' whenever `echo'
could fail, and similarly use `printf %s' instead of `echo -n'.
For portable shell scripts, instead, it is suggested to use a
here-document like this:
cat <<EOF
$foo
EOF
Alternatively, M4sh provides `AS_ECHO' and `AS_ECHO_N' macros
which choose between various portable implementations: `echo' or
`print' where they work, `printf' if it is available, or else
other creative tricks in order to work around the above problems.