Replace
Find and replace text in a file, a variable or a string
Using shell parameter expansion
Syntax: ${VARNAME//FIND/REPLACE}. The // is necessary for global replacement.
$ x=foo_bar_baz_buzz
$ echo ${x//_/-}
foo-bar-baz-buzz
$ echo ${x/_/-}
foo-bar_bazz_buzz
Using sed and a regex pattern
Regex substitution is used in this guide. Test your pattern at regex101.com.
Syntax: s/FIND/REPLACE/g.
The g is for global and is more useful for files and multi-line strings than for one-line strings.
Example:
s/foo/bar/g
Use g for global. Add I after g for case insensitive flag.
Some characters must be escaped such as with backslash.
Replace word
Using a string.
$ echo 'football' | sed 's/foo/bar/g'
bartball
$ echo 'football' | sed 's/foo/bar/g'
tball
Using a variable.
$ x='football'
$ echo $x | sed 's/foo/bar/g'
bartball
Replace newline character
Given text:
$ echo 'Hello\nworld'
Hello
world
Note that those also remove a trailing newline.
Note you don’t need to escape \n as \\n.
sed
Using sed. This doesn’t work on macOS sed though.
$ echo 'Hello\nworld' | sed 's/\n/ /'
Hello world
tr
Using tr.
$ echo 'Hello\nworld' | tr '\n' ' '
Hello world
Replace character with a newline character
Use \ followed by pressing enter. Using \n doesn’t seem to work here.
sed
$ echo 'Hello,World' | sed -e 's/,/\
/g'
Hello
World
tr
Both of these work.
$ echo "Hello:world" | tr ':' '\n'
Hello
world
$ echo "Hello:world" | tr ':' '
'
Hello
world
Make sure that the 2nd argument for tr is ' followed by enter - if you press space and then enter then it doesn’t work.
Backup
The default use of sed will just print, so use the inline flag to update the file.
You can optionally provide an extension - typically .bak. This will create a backup of the file before overrwriting it.
Note that this flag works differently on macOS and Linux.
Here assume pattern is like 's/foo/bar/g' and the PATH could be * or a filename.
This works on Linux.
$ sed -i PATTERN PATH
$ sed -i .bak PATTERN PATH
On macOS you have to provide an argument - even if its an empty string for no backup.
$ sed -i '.bak' PATTERN PATH
$ sed -i '' PATTERN PATH
Replace word in file
Replace foo with bar in file.txt and print to the console.
sed -i 's/foo/bar/g' file.txt
Note: Use -i flag to update the file in place. Or remove it to just preview in the console.
From tutorial
Replace multiple words in a file
Use multiple replacements in one command
Separate with semicolon
sed -i 's/foo/bar/g; s/fizz/buzz/g' file.txt
Separate with newline
sed -i 's/foo/bar/g
s/fizz/buzz/g
' file.txt
Advanced
For more control, you can use you can use an intermediate term. Like the arbitrary ~~ below.
Here we rename foo to bar but preserve instances of food.
sed -i 's/food/~~/g; s/foo/bar/g; s/~~/food/g' file.txt
Note there may be a cleaner way to do this, such a with regex in the console or your IDE. Maybe with grep or find.
Replace a word in multiple files
Replace foo with bar in all files in a directory.
sed -i 's/foo/bar/g' *
sed -i 's/foo/bar/g' foo/*
I don’t think it goes into a directory though and it gives errors on processing directory. So that is why using find and setting type as file as later in this guide is useful.
Delete lines
Delete an entire line matching pattern.
sed
$ sed -i '' '/foo/d' file.txt
Use the reverse match.
$ sed -i '' -n '/foo/!p' file.txt
tr
Using --delete flag.
$ tr -d 'foo' < file.txt
awk
Use the reverse match.
Note that > will start overwriting immediately so you need a temp file.
$ awk '!/foo/' file.txt > temp && mv temp file.txt
grep
Use the reverse match.
$ grep -v "foo" file.txt > temp && mv temp file.txt
Replace and output a new file
$ sed -e s/spam/eggs/ foo.html > bar.html
Combine sed and find
Use find to find files and replace in-line, while the sed part is your transformation.
This is useful to apply to files only since sed will give an error on in-place replacements against directories. Also, find is suited for finding files nested in directories.
General:
$ find . -type f -exec sed -i 'PATTERN' {} \;
e.g.
$ find . -type f -exec sed -i 's/foo/bar/g' {} \;
Replace tabs with 2 spaces in a directory:
$ find . -type f -exec sed -i 's/\t/ /g' {} \;
From StackOverflow.
You can narrow down the name. Here is a glob. Make sure to use a star that is quoted. Also the star glob will not match hidden directories - this will help you avoid accidentally updating and breaking .git.
$ find . -type f -name '*' -exec 'sed -i .bak -e "PATTERN" {} +'
$ find . -exec sed -i '' -e 'PATTERN' {} \;
-e command
Append the editing commands specified by the command argument to the list of commands.
Or reverse the order so find is used by sed. I found this easier than the syntax above which I copied but kept getting errors on.
$ sed -i 's/foo/bar/g' $(find . -type f)
Install sed
If you are used to the GNU (Linux) sed, you can set it up on macOS too.
$ brew install gnu-sed
Add to .bashrc or .zshrc to make is accesible.
export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"