I'm trying to use SED to extract text from a log file.
I can do a search-and-replace without too much trouble:
sed 's/foo/bar/' mylog.txt
However, I want to make the search case-insensitive. From what I've googled, it looks like appending i
to the end of the command should work:
sed 's/foo/bar/i' mylog.txt
However, this gives me an error message:
sed: 1: "s/foo/bar/i": bad flag in substitute command: 'i'
What's going wrong here, and how do I fix it?
I'm on macOS, in case it matters.
The sed FAQ addresses the closely related case-insensitive search. It points out that a) many versions of sed support a flag for it and b) it's awkward to do in sed, you should rather use awk or Perl.
But to do it in POSIX sed, they suggest three options (adapted for substitution here):
Convert to uppercase and store original line in hold space; this won't work for substitutions, though, as the original content will be restored before printing, so it's only good for insert or adding lines based on a case-insensitive match.
Maybe the possibilities are limited to
FOO
,Foo
andfoo
. These can be covered byTo search for all possible matches, one can use bracket expressions for each character:
Another work-around for
sed
on Mac OS X is to installgsed
from MacPorts or HomeBrew and then create the aliassed='gsed'
.The Mac version of
sed
seems a bit limited. One way to work around this is to use a linux container (via Docker) which has a useable version ofsed
:I had a similar need, and came up with this:
this command to simply find all the files:
this one to exclude this_shell.sh (in case you put the command in a script called this_shell.sh), tee the output to the console to see what happened, and then use sed on each file name found to replace the text foo with bar:
I chose this method, as I didn't like having all the timestamps changed for files not modified. feeding the grep result allows only the files with target text to be looked at (thus likely may improve performance / speed as well)
be sure to backup your files & test before using. May not work in some environments for files with embedded spaces. (?)
If you are doing pattern matching first, e.g.,
then you want to put the
I
after the pattern:Example:
returns
willma
; without theI
, it returns the string untouched (Fred
).To be clear: On macOS - as of Mojave (10.14) -
sed
- which is the BSD implementation - does NOT support case-insensitive matching - hard to believe, but true. The formerly accepted answer, which itself shows a GNUsed
command, gained that status because of theperl
-based solution mentioned in the comments.To make that Perl solution work with foreign characters as well, via UTF-8, use something like:
-C
turns on UTF-8 support for streams and files, assuming the current locale is UTF-8-based.-Mutf8
tells Perl to interpret the source code as UTF-8 (in this case, the string passed to-pe
) - this is the shorter equivalent of the more verbose-e 'use utf8;'.
Thanks, Mark Reed(Note that using
awk
is not an option either, asawk
on macOS (i.e., BWK awk, a.k.a. BSD awk) appears to be completely unaware of locales altogether - itstolower()
andtoupper()
functions ignore foreign characters (andsub()
/gsub()
don't have case-insensitivity flags to begin with).)