You are writing a script that will run on multiple versions of Unix and Linux and you
need echo to behave consistently even if it is not running on bash.
Use printf “%b” whatever, or test for the system and set xpg_echo using shopt -s xpg_ echo as needed.
If you omit the “%b” format string (for example, printf whatever), then printf will try
to interpret any % characters in whatever, which is probably not what you want.
The “%b” format is an addition to the standard printf format that will prevent that misinterpretation and also expand backslash escape sequences in whatever.
Setting xpg_echo is less consistent since it only works on bash.
It can be effective if you are sure that you’ll only every run under bash, and not under sh or another similar shell that doesn’t use xpg_echo.
Using printf requires changes to how you write echo statements, but it’s defined by
POSIX and should be consistent across any POSIX shell anywhere.
Specifically, you have to write printf “%b” instead of just echo.
In some shells, built-in echo behaves differently than the external echo used on other systems.
This is not always obvious when running on Linux since /bin/sh is actually bash (usually; it could also be dash on Ubuntu 6.10+), and there are similar circumstances on some BSDs.
The difference is in how echo does or does not expand backslash- escape sequences.
Shell built-in versions tend not to expand, while external versions (e.g., /bin/echo and /usr/bin/echo) tend to expand; but again, that can change from system to system.
Typical Linux (/bin/bash):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
$ type -a echo echo is a shell builtin echo is /bin/echo $ builtin echo "one\ttwo\nthree" one\ttwo\nthree\n $ /bin/echo "one\ttwo\nthree" one\ttwo\nthree\n $ echo -e "one\ttwo\nthree" one ➝ two three $ /bin/echo -e "one\ttwo\nthree" one ➝ two three $ shopt -s xpg_echo $ builtin echo "one\ttwo\nthree" one ➝ two three $ shopt -u xpg_echo $ builtin echo "one\ttwo\nthree" one\ttwo\nthree\n |
Typical BSD (/bin/csh, then /bin/sh):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
$ which echo echo: shell built-in command. $ echo "one\ttwo\nthree" one\ttwo\nthree\n $ /bin/echo "one\ttwo\nthree" one\ttwo\nthree\n $ echo -e "one\ttwo\nthree" -e one\ttwo\nthree\n $ /bin/echo -e "one\ttwo\nthree" -e one\ttwo\nthree\n $ printf "%b" "one\ttwo\nthree" one ➝ two three $ /bin/sh $ echo "one\ttwo\nthree" one\ttwo\nthree\n $ echo -e "one\ttwo\nthree" one ➝ two three $ printf "%b" "one\ttwo\nthree" one ➝ two three |
Solaris 10 (/bin/sh):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$ which echo /usr/bin/echo $ type echo echo is a shell builtin $ echo "one\ttwo\nthree" one ➝ two three $ echo -e "one\ttwo\nthree" -e one ➝ two three $ printf "%b" "one\ttwo\nthree" one ➝ two three |