ARG_MAX
| Shells
| portability
| permissions
| UUOC
| ancient
| -
| ../Various
| HOME
$() vs )
| IFS
| using siginfo
| nanosleep
| line charset
| locale
echo(1) and printf(1)2010-06-13 (see recent changes)
About the history, from Gunnar Ritter in <3B98D626.HL11B46E@bigfoot.de> (bad translation is mine),
motivating this page:
"echo -n" came from Research Unix via 32V to BSD,
escape sequences came from PWB/Unix to AT&T System III,
and eventually it got mixed up.
echo(1) is only portable if you omit flags and escape sequences.
Use printf(1) instead, if you need more.
printf was introduced with the Ninth Edition System.
It was added to more widely distributed Unix flavours with 4.3BSD-Reno and with SVR4.
Meanwhile it's required by POSIX/SUSv2.
But it's not only about traditional portability of echo, even POSIX forbids options:
SUSv2
states that "Implementations will not support any options."
SUSv3
enforces this with "Implementations shall not support any options."
If you still have to supress newline with echo for some reason, a possible workaround is the following code:
if [ "X`echo -n`" = "X-n" ]; then
echo_n() { echo ${1+"$@"}"\c"; }
else
echo_n() { echo -n ${1+"$@"}; }
fi
A closer look at echo implementations:
| Operating System | Bourne sh | Korn sh | echo(1) | printf(1) | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| -n | -e | \c | \a | \xxx | -n | -e | \c | \a | \xxx | -n | -e | \c | \a | \xxx | available | |
| Version 7 | (no built-in) | N/A | x | |||||||||||||
| System III | (no built-in) | N/A | x | x | ||||||||||||
| SINIX V5.20 | x | x | -e | -e | -e | (N/A per default) | x | x | -e | -e | -e | |||||
| SunOS 4 ucb [s4bsd] | x | (N/A per default) | x | |||||||||||||
| SunOS 5 ucb [s5bsd] | x | x | x | x | ||||||||||||
| SunOS 4 sysv [s4sv] | x | x | (N/A per default) | x | x | |||||||||||
| EP/IX 2.2.1AA | x | x | x | x | x | x | x | x | ||||||||
| Unicos 9.0.2.2 | N/A | x | x | x | x | x | x | x | ||||||||
| HP-UX 8.07,9.03 | x | x | x | x | x | x | x | x | ||||||||
| HP-UX 10/11.x [hpux] | x | x | x | x | x | x | x | x | x | |||||||
| AIX 4.3 | x | x | x | x | x | x | x | x | x | |||||||
| SunOS 5 sysv [s5sv] | x | x | x | x | x | x | x | x | x | |||||||
| OSF1/V4, V5 | x | x | x | x | x | x | x | x | x | x | ||||||
| MUNIX 3.2 (SVR3) | x | x | x | (N/A per default) | x | x | x | |||||||||
| AIX 3.2 | x | x | x | x | x | x | x | x | x | x | x | |||||
| IRIX 5.3, 6.5 | x | x | x | x | x | x | x | x | x | x | x | |||||
| OpenServer 506 | x | x | x | x | x | x | x | x | x | x | x | x | ||||
| Almquist sh | pdksh | echo(1) | printf(1) | |||||||||||||
| -n | -e | \c | \a | \xxx | -n | -e | \c | \a | \xxx | -n | -e | \c | \a | \xxx | ||
| FreeBSD 4.3 | x | x | -e | -e | -e | see below | x | x | x | |||||||
| NetBSD 1.5.1 | x | x | -e | -e | see below | x | x | |||||||||
| BSD/OS 4.1 | x | x | -e | -e | see below | x | x | |||||||||
| OpenBSD 2 | [pdksh] | see below | x | x | ||||||||||||
| Almquist sh | echo(1) | printf(1) | ||||||||||||||
| -n | -e | \c | \a | \xxx | -n | -e | \c | \a | \xxx | |||||||
| Minix 3.1.0 [minix3] | x | x | -e | -e | x | x | -e | -e | x | |||||||
| echo(1) | printf(1) | |||||||||||||||
| -n | -e | \c | \a | \xxx | ||||||||||||
| POSIX | x | x | x | x | ||||||||||||
| GNU 2.0.15 | x | x | -e | -e | -e | x | ||||||||||
| Busybox 1.01 [busybox] | x | x | -e | -e | -e | x | ||||||||||
| Shell Built-ins | -n | -e | \c | \a | \xxx | printf built-in |
|---|---|---|---|---|---|---|
| original ash | x | x | x | x | ||
| debian ash before 0.3.5-7 | x | x | x | x | ||
| debian ash/dash since 0.3.5-7 | x | x | x | x | since ash-0.3.8-1 | |
| ksh88 | [see above] | |||||
| ksh93 | x | x | x | x | x | |
| pdksh(5.2.14) | x | x | x | x | x | |
| posh-0.5.4 | x | x | x | x | ||
| mksh-R28/R39 | x | x | x | x | x | |
| bash-1.14.6/2.x/3.x/4.0 | x | x | -e | -e | -e | since 2.02 |
| zsh-3.0.8/4.3.2 called as zsh | x | x | x | x | x | since 4.1.0 |
| zsh-3.0.8/4.3.2 called as sh | x | x | -e | -e | -e | since 4.1.0 |
| printf built-in | ||||||
| NetBSD sh (almquist) | [see above] | added 11/'02, NetBSD 2.0 | ||||
| FreeBSD sh (almquist) | [see above] | removed 11/'01, FreeBSD 5.0 | ||||
| OpenBSD sh (pdksh) | [see above] | no | ||||
| "-e": | feature enabled when using this flag |
| [hp-ux]: | On HP-UX 10, the POSIX shell (/bin/sh) behaves like the Korn shell |
| [s4bsd]: | SunOS 4 with /usr/bin preceding /usr/5bin in PATH. The echo builtin mimics the according external command.
|
| [s5bsd]: | SunOS 5 enables BSD compatibility, if /usr/ucb precedes
/usr/bin in PATH. On x86, this is also enabled, if SYSV3 is set in the environment
|
| [s4sv]: | SunOS 4 with /usr/5bin preceding /usr/bin in PATH. The SysV version knows the escape sequences "\b \c \f \n \r \t \v \xxx", but not "\a" (ASCII-BEL). |
| [minix3]: | printf(1) has not been documented yet at the time of this writing (06/2010, v3.1.6).
It was added in jan '87 and released with v2.0.3. It's located in /usr/bin/.
|
| [busybox]: | busybox added printf(1) at about v0.27, may 1995.
|
The following table lists tests results.
Keep in mind that some examples use unportable input to illustrate variations.
Idea to examine this from Stephane Chazelas.
| commandline | bash-2.05b | bash-4.0 | ash-0.4.0 | dash- 0.5.5.1 | ksh93-k | ksh93-t | GNU core- utils 5.97 | OpenServer 5.0.6 | EP/IX 2.2.1A | SunOS 5.9 |
|---|---|---|---|---|---|---|---|---|---|---|
| printf '\a' | od -b -A n|sed 2d | 007 | 007 | 007 | 007 | 007 | 007 | 007 | 007 | 007 | 007 |
| printf '\b' | od -b -A n|sed 2d | 010 | 010 | 010 | 010 | 010 | 010 | 010 | 010 | 010 | 010 |
| printf '\t' | od -b -A n|sed 2d | 011 | 011 | 011 | 011 | 011 | 011 | 011 | 011 | 011 | 011 |
| printf '\n' | od -b -A n|sed 2d | 012 | 012 | 012 | 012 | 012 | 012 | 012 | 012 | 012 | 012 |
| printf '\v' | od -b -A n|sed 2d | 013 | 013 | 013 | 013 | 013 | 013 | 013 | 013 | 013 | 013 |
| printf '\f' | od -b -A n|sed 2d | 014 | 014 | 014 | 014 | 014 | 014 | 014 | 014 | 014 | 014 |
| printf '\r' | od -b -A n|sed 2d | 015 | 015 | 015 | 015 | 015 | 015 | 015 | 015 | 015 | 015 |
| printf '.\c.' | od -b -A n|sed 2d | 056 134 143 056 | 056 134 143 056 | 056 | 056 134 143 056 | 056 143 056 | 056 156 | 056 134 143 056 | 134 143 | 056 134 143 056 | 056 134 143 056 |
| printf '%b' '.\c.' | od -b -A n|sed 2d | 056 | 056 | 056 | 056 | 056 | 056 | 056 | 170 | 056 | 056 |
| printf '\d' | od -b -A n|sed 2d | 134 144 | 134 144 | 134 144 | 134 144 | 144 | 144 | 134 144 | 134 144 | 134 144 | 134 144 |
| printf '\g' | od -b -A n|sed 2d | 134 147 | 134 147 | 134 147 | 134 147 | 147 | 147 | 134 147 | 134 147 | 134 147 | 134 147 |
| printf '\h' | od -b -A n|sed 2d | 134 150 | 134 150 | 134 150 | 134 150 | 150 | 150 | 134 150 | 134 150 | 134 150 | 134 150 |
| printf '\i' | od -b -A n|sed 2d | 134 151 | 134 151 | 134 151 | 134 151 | 151 | 151 | 134 151 | 134 151 | 134 151 | 134 151 |
| printf '\j' | od -b -A n|sed 2d | 134 152 | 134 152 | 134 152 | 134 152 | 152 | 152 | 134 152 | 134 152 | 134 152 | 134 152 |
| printf '\k' | od -b -A n|sed 2d | 134 153 | 134 153 | 134 153 | 134 153 | 153 | 153 | 134 153 | 134 153 | 134 153 | 134 153 |
| printf '\l' | od -b -A n|sed 2d | 134 154 | 134 154 | 134 154 | 134 154 | 154 | 154 | 134 154 | 134 154 | 134 154 | 134 154 |
| printf '\m' | od -b -A n|sed 2d | 134 155 | 134 155 | 134 155 | 134 155 | 155 | 155 | 134 155 | 134 155 | 134 155 | 134 155 |
| printf '\o' | od -b -A n|sed 2d | 134 157 | 134 157 | 134 157 | 134 157 | 157 | 157 | 134 157 | 134 157 | 134 157 | 134 157 |
| printf '\p' | od -b -A n|sed 2d | 134 160 | 134 160 | 134 160 | 134 160 | 160 | 160 | 134 160 | 134 160 | 134 160 | 134 160 |
| printf '\q' | od -b -A n|sed 2d | 134 161 | 134 161 | 134 161 | 134 161 | 161 | 161 | 134 161 | 134 161 | 134 161 | 134 161 |
| printf '\s' | od -b -A n|sed 2d | 134 163 | 134 163 | 134 163 | 134 163 | 040 | 163 | 134 163 | 134 163 | 134 163 | 134 163 |
| printf '\u' | od -b -A n|sed 2d | 134 165 | 134 165 | N/A | 134 165 | 165 | 000 | 134 165 | 134 165 | 134 165 | 134 165 |
| printf '\w' | od -b -A n|sed 2d | 134 167 | 134 167 | 134 167 | 134 167 | 167 | 167 | 134 167 | 134 167 | 134 167 | 134 167 |
| printf '\y' | od -b -A n|sed 2d | 134 171 | 134 171 | 134 171 | 134 171 | 171 | 171 | 134 171 | 134 171 | 134 171 | 134 171 |
| printf '\z' | od -b -A n|sed 2d | 134 172 | 134 172 | 134 172 | 134 172 | 172 | 172 | 134 172 | 134 172 | 134 172 | 134 172 |
| printf '\e' | od -b -A n|sed 2d | 033 | 033 | 134 145 | 134 145 | 145 | 033 | 033 | 033 | 033 | 033 |
| printf '\033' | od -b -A n|sed 2d | 033 | 033 | 033 | 033 | 033 | 033 | 033 | 033 | 033 | 033 |
| printf '\33' | od -b -A n|sed 2d | 033 | 033 | 033 | 033 | 033 | 033 | 033 | 033 | 033 | 033 |
| printf '%b' '\33' | od -b -A n|sed 2d | 033 | 033 | 033 | 033 | 134 063 063 | 134 063 063 | 033 | 033 | 033 | 033 |
| printf '%b' '\033' | od -b -A n|sed 2d | 033 | 033 | 033 | 033 | 033 | 033 | 033 | 033 | 033 | 033 |
| printf '%b' '\0033' | od -b -A n|sed 2d | 033 | 033 | 033 | 033 | 033 | 033 | 033 | 033 | 033 | 033 |
| printf '\0033' | od -b -A n|sed 2d | 033 | 003 063 | 003 063 | 003 063 | 003 063 | 003 063 | 003 063 | 003 063 | 003 063 | 033 |
| printf '\0033' | od -b -A n|sed 2d | 033 | 003 063 | 003 063 | 003 063 | 003 063 | 003 063 | 003 063 | 003 063 | 003 063 | 033 |
| commandline | bash-2.05b | bash-4.0 | ash-0.4.0 | dash- 0.5.5.1 | ksh93-k | ksh93-t | GNU core- utils 5.97 | OpenServer 5.0.6 | EP/IX 2.2.1A | SunOS 5.9 |
About the table:
<http://www.in-ulm.de/~mascheck/various/echo+printf/>
Sven Mascheck