How to search and replace multiple needles by one word via one expression?

9,189

Solution 1

Use -r option for extended regexp syntax:

sed -r -e 's/foo|bar/narf/g'

Otherwise escape the disjunction as \|:

sed -e 's/foo\|bar/narf/g'

Solution 2

There are many variations on regular expression syntax. The very first tools in the unix world that had regular expressions did not have the full capabilities of regular expressions, only character sets ([…] and .), repetition (*) and line anchors (^ and $). Basic regular expressions only have these operators. Sed is an old-school tool and uses basic regexps.

Many sed implementations have extensions for full regexp matching. Because the character | stands for itself, you need to use \| for alternation, and similarly \( and \) for grouping. Note that the POSIX standard does not mandate that \| be supported in basic regular expressions, and some systems (e.g. OpenBSD) do not have it.

Some versions of sed have an option to switch to extended regular expressions, where (…) is used for grouping and | for alternation. With GNU sed (i.e. under Linux or Cygwin) or Busybox, pass the -r option. On FreeBSD or OSX, pass the -E option.

If your sed does not have alternation, you can call awk instead. It's mandated by POSIX, but a bit verbose for this task, and it does not support backreferences.

awk '{gsub(/foo|bar/, "narf")}' <fileName.old >fileName.new

By the way, only GNU and Busybox sed support file replacement in place. Awk and other versions of sed don't. See Can I make `cut` change a file in place?

If you have Perl, it's often handy in a one-tool-does-all kind of way for text processing one-liners. Most of what's easy in sed, awk and the rest isn't much more difficult in Perl, and you can get away with learning a single (if complex) tool.

perl -i -pe 's/foo|bar/narf/g' fileName
Share:
9,189

Related videos on Youtube

k0pernikus
Author by

k0pernikus

I am Philipp Kretzschmar, a backend developer from Hamburg working at Demvsystem. You can find me on github. Or twitter. My main weapons of choice are: php TypeScript (I don't want to write plain JavaScript anymore) and nodejs I play around with: Java python rust I used to write some scala, but for now I don't want to go there anymore. I feel most comfortable on a unix-like system featuring a powerful bash. (This excludes MacOS.) I love to code within JetBrains's flavored IDEs, e.g. IntelliJ, PhpStorm, WebStorm and using the IdeaVim plugin and having a docker-compose stack to develop on.

Updated on September 18, 2022

Comments

  • k0pernikus
    k0pernikus over 1 year

    Assume you have a text file:

    foo fnord bar
    bizz foo poit
    

    And now I would want to replace both "foo" and "bar" into "narf".

    I know I could use:

     sed -e 's/foo/narf/g' -e 's/bar/narf/g' fileName
    

    Yet I would like to work with an OR-operator that tells the regex to match both needles via one expression.

    Hitting some manuals I suppose the pipe should fit my needs but I tried

    sed -e 's/foo|bar/narf/g' -i fileName
    

    and it didn't work and it's not even throwing an error.

    What am I doing wrong here?