echo(1) and printf(1)

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

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 \0xxx 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)

  • System specific echo implementations, and availability of printf:
    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 specific echo implementations:
    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

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

Why is printf better than echo?

 

I have heard that printf is better than echo. I can recall only one instance from my experience where I had to use printf because echo didn’t work for feeding some text into some program on RHEL 5.8 but printf did. But apparently, there are other differences, and I would like to inquire what they are as well as if there are specific cases when to use one vs the other.

shareimprove this question
 

5 Answers

up vote506down voteaccepted

Basically, it’s a portability (and reliability) issue.

Initially, echo didn’t accept any option and didn’t expand anything. All it was doing was outputting its arguments separated by a space character and terminated by a newline character.

Now, someone thought it would be nice if we could do things like echo "\n\t" to output newline or tab characters, or have an option not to output the trailing newline character.

They then thought harder but instead of adding that functionality to the shell (like perl where inside double quotes, \t actually means a tab character), they added it to echo.

David Korn realized the mistake and introduced a new form of shell quotes: $'...' which was later copied by bash and zsh but it was far too late by that time.

Now when a standard Unix echo receives an argument which contains the two characters \ and t, instead of outputting them, it outputs a tab character. And as soon as it sees \c in an argument, it stops outputting (so the trailing newline is not output either).

Other shells/Unix vendors/versions chose to do it differently: they added a -e option to expand escape sequences, and a -n option to not output the trailing newline. Some have a -E to disable escape sequences, some have -n but not -e, the list of escape sequences supported by one echo implementation is not necessarily the same as supported by another.

Sven Mascheck has a nice page that shows the extent of the problem.

On those echo implementations that support options, there’s generally no support of a -- to mark the end of options (zsh and possibly others support - for that though), so for instance, it’s difficult to output "-n" with echo in many shells.

On some shells like bash1 or ksh932 or yash ($ECHO_STYLE variable), the behavior even depends on how the shell was compiled or the environment (GNU echo’s behaviour will also change if $POSIXLY_CORRECT is in the environment). So two bash echos, even from the same version of bash are not guaranteed to behave the same.

POSIX says: if the first argument is -n or any argument contains backslashes, then the behavior is unspecified. bash echo in that regard is not POSIX in that for instance echo -e is not outputting -e<newline> as POSIX requires. The Unix specification is stricter, it prohibits -n and requires expansion of some escape sequences including the \c one to stop outputting.

Those specifications don’t really come to the rescue here given that many implementations are not compliant.

All in all, you don’t know what echo "$var" will output unless you can make sure that $var doesn’t contain backslash characters and doesn’t start with -. The POSIX specification actually does tell us to use printf instead in that case.

So what that means is that you can’t use echo to display uncontrolled data. In other words, if you’re writing a script and it is taking external input (from the user as arguments, or file names from the file system…), you can’t use echo to display it.

This is OK:

echo >&2 Invalid file.

This is not:

echo >&2 "Invalid file: $file"

(Though it will work OK with some (non Unix) echo implementations like bash’s when the xpg_echooption has not been enabled in one way or another like at compilation time or via the environment).

printf, on the other hand is more reliable, at least when it’s limited to the basic usage of echo.

printf '%s\n' "$var"

Will output the content of $var followed by a newline character regardless of what character it may contain.

printf '%s' "$var"

Will output it without the trailing newline character.

Now, there also are differences between printf implementations. There’s a core of features that is specified by POSIX, but then there are a lot of extensions. For instance, some support a %q to quote the arguments but how it’s done varies from shell to shell, some support \uxxxx for unicode characters. The behavior varies for printf '%10s\n' "$var" in multi-byte locales, there are at least three different outcomes for printf %b '\123'

But in the end, if you stick to the POSIX feature set of printf and don’t try doing anything too fancy with it, you’re out of trouble.

But remember the first argument is the format, so shouldn’t contain variable/uncontrolled data.

A more reliable echo can be implemented using printf, like:

echo() ( # subshell for local scope for $IFS
  IFS=" " # needed for "$*"
  printf '%s\n' "$*"
)

echo_n() (
  IFS=" "
  printf %s "$*"
)

echo_e() (
  IFS=" "
  printf '%b\n' "$*"
)

The subshell (which implies spawning an extra process in most shell implementations) can be avoided using local IFS with many shells, or by writing it like:

echo() {
  if [ "$#" -gt 0 ]; then
     printf %s "$1"
     shift
  fi
  if [ "$#" -gt 0 ]; then
     printf ' %s' "$@"
  fi
  printf '\n'
}

Notes

1. how bash’s echo behaviour can be altered.

With bash, at run time, there are two things that control the behaviour or echo (beside enable -n echo or redefining echo as a function or alias): the xpg_echo bash option and whether bash is in posix mode. posix mode can be enabled if bash is called as sh or if POSIXLY_CORRECT is in the environment or with the the posix option:

Default behaviour on most systems:

$ bash -c 'echo -n "\0101"'
\0101% # the % here denotes the absence of newline character

xpg_echo expands sequences as Unix requires:

$ BASHOPTS=xpg_echo bash -c 'echo "\0101"'
A

It still honours -n and -e (and -E):

$ BASHOPTS=xpg_echo bash -c 'echo -n "\0101"'
A%

With xpg_echo and POSIX mode:

$ env BASHOPTS=xpg_echo POSIXLY_CORRECT=1 bash -c 'echo -n "\0101"'
-n A
$ env BASHOPTS=xpg_echo sh -c 'echo -n "\0101"' # (where sh is a symlink to bash)
-n A
$ env BASHOPTS=xpg_echo SHELLOPTS=posix ARGV0=sh bash -c 'echo -n "\0101"'
-n A
$ env BASHOPTS=xpg_echo SHELLOPTS=posix bash -c 'echo -n "\0101"'
-n A

This time, bash is both POSIX and Unix conformant. Note that in POSIX mode, bash is still not POSIX conformant as it doesn’t output -e in:

 $ env SHELLOPTS=posix bash -c 'echo -e'

 $

The default values for xpg_echo and posix can be defined at compilation time with the --enable-xpg-echo-default and --enable-strict-posix-default options to the configure script. That’s typically what recent versions of OS/X do to build their /bin/sh. No Unix/Linux implementation/distribution in their right mind would typically do that for /bin/bash though.

2. How ksh93’s echo behaviour can be altered.

In ksh93, whether echo expands escape sequences or not and recognises options depends on the content of $PATH.

If $PATH contains a component that contains /5bin or /xpg before the /bin or /usr/bincomponent then it behave the SysV/Unix way (expands sequences, doesn’t accept options). If it finds /ucb or /bsd first, then it behaves the BSD3 way (-e to enable expansion, recognises -n). The default is system dependant, BSD on Debian:

$ ksh93 -c 'echo -n' # default -> BSD (on Debian)
$ PATH=/foo/xpgbar:$PATH ksh93 -c 'echo -n' # /xpg before /bin or /usr/bin -> XPG
-n
$ PATH=/5binary:$PATH ksh93 -c 'echo -n' # /5bin before /bin or /usr/bin -> XPG
-n
$ PATH=/ucb:/foo/xpgbar:$PATH ksh93 -c 'echo -n' # /ucb first -> BSD
$ PATH=/bin:/foo/xpgbar:$PATH ksh93 -c 'echo -n' # /bin before /xpg -> default -> BSD

3. BSD for echo -e?

The reference to BSD for the handling of the -e option is misleading here. All those different and incompatible echo behaviours were all introduced at Bell labs:

  • \n, \0ooo in Programmer’s Word Bench UNIX (based on Unix V6), and the rest (\b, \c…) in Unix System IIIRef.
  • -n in Unix V7 (by Denis RitchieRef)
  • -e in Unix V8 (by Denis RitchieRef)

BSDs just descended from Unix V7. FreeBSD echo still doesn’t support -e, though it does support -n like Unix V7 did.

shareimprove this answer
 
53  
wow. did you, like, write unix? – Eliran Malka Feb 13 ’14 at 14:39
29  
Stephane, a good part of the Bash chops I have learned here and there, I owe them to you. Your commitment to sharing what you know is amazing. I guess the least I could do is say … thank-you, you rock friend. – stefgosselin Feb 27 ’14 at 4:29
5  
A lot of early unix development happened in isolation, and good software engineering principles like ‚when you change the interface, change the name‘ were not applied. – Henk Langeveld Mar 14 ’14 at 7:57
4  
As a note, the one (and maybe only) advantage of having echo expand the \x sequences as opposed to the shell as part of the quoting syntax is that you can then output a NUL byte (another arguably mis-design of Unix is those null-delimited strings, where half the system calls (like execve()) can’t take arbitrary sequences of bytes) – Stéphane Chazelas Aug 4 ’15 at 12:15
 

You might want to use printf for its formatting options. echo is useful when it comes to printing the value of a variable or a (simple) line, but that’s all there is to it. printf can basically do what the C version of it can do.

Example usage and capabilities:

Echo

echo "*** Backup shell script ***"
echo
echo "Runtime: $(date) @ $(hostname)"
echo

printf

vech="bike"
printf "%s\n" "$vech"

Sources:

shareimprove this answer
 
    
@0xC0000022L I stand corrected thanks. I didn’t notice I linked to the wrong site in my rush to answer the question. Thank you for your contribution and the correction. – NlightNFotis Feb 22 ’13 at 20:18
5  
Using echo to print a variable can fail if the value of the variable contains meta-characters. – Keith Thompson Apr 29 ’13 at 15:22

One „advantage“, if you want to call it that, would be that you don’t have to tell it like echo to interpret certain escape sequences such as \n. It knows to interpret them and won’t require an -e to do so.

printf "some\nmulti-lined\ntext\n"

(NB: the last \n is necessary, echo implies it, unless you give the -n option)

versus

echo -e "some\nmulti-lined\ntext"

Note the last \n in printf. At the end of the day it’s a matter of taste and requirements what you use: echo or printf.

shareimprove this answer
 
1  
True for /usr/bin/echo and the bash builtin. The dash, ksh and zsh builtin echo does not need -e switch to expand backslash-escaped characters. – manatwork Feb 23 ’13 at 10:35
    
Why the scare quotes? Your wording implies that it isn’t necessarily a real advantage. – Keith Thompson Apr 29 ’13 at 15:26
1  
@KeithThompson: actually all they are meant to imply is that not everyone may consider it an advantage. – 0xC0000022L Apr 29 ’13 at 15:33
    
Could you expand on that? Why wouldn’t it be an advantage? The phrase „if you want to call it that“ implies pretty strongly that you think it isn’t. – Keith Thompson Apr 29 ’13 at 15:36
2  
Or you could just do printf '%s\n' 'foo\bar. – nyuszika7h Mar 9 ’14 at 17:36

One downside of printf is performance because the built-in shell echo is much faster. This comes into play particularly in Cygwin where each instance of a new command causes heavy Windows overhead. When I changed my echo-heavy program from using /bin/echo to the shell’s echo the performance almost doubled. It’s a trade off between portability and performance. It’s not a slam dunk to always use printf.

shareimprove this answer
 
7  
printf is built in most shells nowadays (bash, dash, ksh, zsh, yash, some pdksh derivatives… so includes the shells typically found on cygwin as well). The only notable exceptions are some pdkshderivatives. – Stéphane Chazelas Nov 7 ’14 at 13:52

Also printf is faster in primitive types with respect to the echo. this is because the the type of the data is specified in the code. the difference in the speed is not recognised as countable factor unless you are coding a driver.

shareimprove this answer
 
3  
What do you mean by “primitive types”? – manatwork Feb 23 ’13 at 14:57
3  
I don’t believe that applies to the printf command. It probably doesn’t apply to the printf function, which has to spend time parsing the format string, – Keith Thompson Apr 29 ’13 at 15:25
    
unless coding a driver phew, I’m lucky I did not write this driver in Bash… – Alois Mahdal Dec 18 ’15 at 5:43
1  
If you’re coding a driver, hopefully you aren’t doing it in a shell script. This answer seems to be about some other topic unrelated to the scope of this question. – Caleb Nov 22 ’16 at 6:16

How to search and replace text in all php-files in a directory and it’s subdirectories

I am looking for a shell script that recursively traverses all .php files in a directory and performs a search & replace of a particular text pattern.

The search pattern is quite long ( > 5000 characters) so it might be saved in another textfile for convenience. Also it contains forward slash characters.

edit: i think i figured out the first part:

find . -name „*.php“

but then how do i search & replace in those files?
shell-script text-processing grep find ls
shareimprove this question
edited Jan 17 ’12 at 9:54
asked Jan 17 ’12 at 7:58
clamp

 

It can be done easily with a good combination of sed and xargs.

find . -name „*.php“ | xargs -n 1 echo

will show you the power of xargs.

After that, on a sample file, you can test the regexp, with an inplace change (-i) or a backup change (-i.bak). You can also use an other character to replace ‚/‘ if your pattern/replacement already have one.

At the end, it should looks like :

pattern=`cat /path/to/pattern`; replacement=`cat /path/to/replacement`
find . -name „*.php“ | xargs -n 1 sed -i -e ’s|$pattern|$replacement|g‘

edited Jan 17 ’12 at 10:16 Coren

 

ok thank you! same question here: how would i load the search pattern from a file?

– clamp Jan 17 ’12 at 9:52
something like this, maybe ? pattern=cat /path/to/pattern; replacement=cat /path/to/replacement; find . -name „*.php“ | xargs -n 1 sed -i -e „s/$pattern/$replacement/g“

– Coren Jan 17 ’12 at 10:04

 

thank you! the only problem remaining is that the pattern contains forward slashes which seem to be problematic in the regexp

– clamp Jan 17 ’12 at 10:06

 

you can use an other character than ‚/‘ in sed. For instance, sed -i -e „|$pattern|$replacement|g works well

– Coren Jan 17 ’12 at 10:15

 

thank you! now it runs without errors but it doesnt seem to replace anything. i guess the search pattern is not found. (although it is there). the search pattern contains all kind of characters including tabs, spaces, $, <, > etc. could that be the problem?

– clamp Jan 17 ’12 at 10:22

 

$ is used by bash for variables. you’ll need to escape it with a ‚\‘.

– Coren Jan 17 ’12 at 10:33