Bourne | Ash |  #!  | find | ARG_MAX | Shells | 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)

Behaviour of the "echo" command or the shell built-in, respectively.
Availability of "printf", and variations in its handling of escape sequences.

2010-06-13 (see recent changes)


1.) Variations in echo implementations

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:

Footnotes for the first table

"-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.


2.) printf: variations in the handling of escape seqences

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