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

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

2011年02月27日 (see recent changes)


1.) Variations in echo implementations

History

About the history, from Gunnar Ritter in <3B98D626.HL11B46E@bigfoot.de> (rough translation by me), motivating this page:

"Research Unix -> 32v -> BSD had "-n",
PWB/Unix -> System III -> System V [had] the escape sequences
and then it became a jumble."

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 0円xx
System III (and SVR1) echo knew \b, \c, \f, \n, \r, \t, \\, and 0円xx

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

Portability

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:

"The specification of 0円xxx in echo with the XSI option is intended to behave as UNIX System V behaved as specified by the System V Interface Definition, version 3 (SVID3).
(SVID3 was one of the base documents of the original POSIX.2 standard, but since BSD systems and UNIX System V systems had different behavior for echo,
the original POSIX.2 standard left the behavior unspecified (allowing the then current implementations to continue to behave as they had).
The X/Open Portability Guide, Issue 3 continued to require the behavior as specified in SVID3.
When the original POSIX.2 and XPG3 were merged in a later revision of the standards, we got the XSI option (which required the System V behavior);
but when XSI option support is not claimed the old BSD or System V behavior is allowed."

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 closer look at various implementations

(\a is a representative for the other escape sequences)

Footnotes for the first table

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


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.

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

AltStyle によって変換されたページ (->オリジナル) /