ARG_MAX
| Shells
| whatshell
| portability
| permissions
| UUOC
| ancient
| -
| ../Various
| HOME
$@
"
| echo/printf
| set -e
| test
| tty defs
| tty chars
| $()
vs )
| IFS
| using siginfo
| nanosleep
| line charset
| locale
echo(1) and printf(1)
2011-02-27 (see recent changes)
About the history, from Gunnar Ritter in <3B98D626.HL11B46E@bigfoot.de>
(rough translation by me), motivating this page:
6th edition echo
research unix didn't know any features.
7th edition echo
implemented -n
PWB/Unix1.0 echo
(derived from 6th edition) implemented \n
, \c
, \\
, and \0xx
System III (and SVR1) echo
knew \b
, \c
, \f
, \n
, \r
,
\t
, \\
, and \0xx
Nowadays, echo(1)
is only portable if you omit flags and escape sequences.
Use printf(1)
instead, if you need more than plain text.
printf
was introduced with the Ninth Edition System
(reference in SUSv3).
It was added to more widely distributed Unix flavours with 4.3BSD-Reno and with SVR4.
Meanwhile printf
is required by POSIX
(SUSv1).
Traditional portability of echo is one issue. But what does POSIX say about options and backslash sequences?
POSIX doesn't support plain options:
SUSv2
states that "Implementations will not support any options."
Since SUSv3
this reads "Implementations shall not support any options."
But the BSD-like behaviour of suppressing newline with "-n
" is not always forbidden:
The behaviour with an operand containing "-n" and also the behaviour about backslash sequences
is implementation defined.
This gets the various traditional implementations into the boat.
But if the XSI option (X/Open System Interfaces) is supported on the system, then echo is well defined
and intended to behave
as specified by the System V Interface Definition, version 3:
"-n
" is not recognized and backslash sequences are defined.
More background about this distinction is
explained by Don Cragun on the austin group mailing list:
If you still have to supress newline with echo for some reason
(with the same script on different systems),
a possible workaround is the following code
( ${1+"$@"}
instead of "
addresses ancient pre-SVR3 shells):
$@
"
if [ "X`echo -n`" = "X-n" ]; then echo_n() { echo ${1+"$@"}"\c"; } else echo_n() { echo -n ${1+"$@"}; } fi
(\a
is a representative for the other escape sequences)
Operating System | Bourne sh | Korn sh (88) | 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 | |||||||||||
SunOS 5 sysv | x | x | x | x | x | x | x | 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 | |||||||
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 | ||||
UnixWare 7.1.4 | 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 2.1 | x | x | -e | -e | -e | 5.2.14 see below | x | x | ||||||||
FreeBSD 2.2, 4.3, 7.1 | x | x | -e | -e | -e | 5.2.14 see below | x | x | x | |||||||
NetBSD 1.5.1, 5.1 | x | x | -e | -e | -e | 5.2.14 see below | x | x | ||||||||
BSD/OS 4.1 | x | x | -e | -e | -e | 5.2.12 see below | x | x | ||||||||
OpenBSD 2 | [pdksh] | 5.2.14 see below | x | x | ||||||||||||
Minix 3.1.0 [minix3] | x | x | -e | -e | - | x | x | -e | -e | x | ||||||
echo(1) | printf(1) | |||||||||||||||
-n | -e | \c | \a | \xxx | ||||||||||||
POSIX XSI (SysV-like) | x | x | x | x | ||||||||||||
POSIX | ? | ? | ? | ? | 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 | |
ksh86 EP/IX2.2.1AA | x | x | ||||
ksh88 | [see above] | |||||
ksh93-d .. -q | x | x | x | x | x | |
ksh93-r .. | x | 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/R52 | x | x | x | x | x | |
bash-1.14.6/2.x/3.x/4.0 called as bash or sh | 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 |
"?" | implementation defined |
[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.
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 | OSF/1 V4.0B | 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 | 007 |
printf '\b' | od -b -A n|sed 2d | 010 | 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 | 011 |
printf '\n' | od -b -A n|sed 2d | 012 | 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 | 013 |
printf '\f' | od -b -A n|sed 2d | 014 | 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 | 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 134 143 056 | 056 134 143 056 |
printf '%b' '.\c.' | od -b -A n|sed 2d | 056 | 056 | 056 | 056 | 056 | 056 | 056 | 056 | 056 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 134 172 | 134 172 |
printf '\e' | od -b -A n|sed 2d | 033 | 033 | 134 145 | 134 145 | 145 | 033 | 033 | 033 | 033 | 033 | 033 |
printf '\033' | od -b -A n|sed 2d | 033 | 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 | 033 |
printf '%b' '\33' | od -b -A n|sed 2d | 033 | 033 | 033 | 033 | 134 063 063 | 134 063 063 | 033 | 033 | N/A | 033 | 033 |
printf '%b' '\033' | od -b -A n|sed 2d | 033 | 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 | 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 | 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 | 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 | OSF/1 V4.0B | EP/IX 2.2.1A | SunOS 5.9 |
printf '%d\n' '"a' | 97 | 97 | 97 | 97 | 97 | 97 | 97 | 97 | 97 | 2146938837 | 97 |
<http://www.in-ulm.de/~mascheck/various/echo+printf/>
Sven Mascheck