macos 不区分大小写的搜索并替换为 sed
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4412945/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Case-insensitive search and replace with sed
提问by Craig Walker
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 从日志文件中提取文本。我可以毫不费力地进行搜索和替换:
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:
但是,我想让搜索不区分大小写。从我用谷歌搜索的内容来看,似乎附加i
到命令的末尾应该有效:
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?
这里出了什么问题,我该如何解决?
采纳答案by mklement0
To be clear: On macOS- as of Mojave (10.14) - sed
- which is the BSDimplementation - 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 the perl
-based solution mentioned in the comments.
需要明确的是:在macOS 上- 从 Mojave (10.14) 开始 -sed
这是BSD实现 - 不支持不区分大小写的匹配- 难以置信,但确实如此。在以前接受的答案,这本身就说明一个GNUsed
命令,获得因为这种地位perl
在评论中提到基于解决方案。
To make that Perl solutionwork with foreign charactersas well, via UTF-8, use something like:
要使Perl 解决方案也适用于外来字符,请通过 UTF-8,使用以下内容:
perl -C -Mutf8 -pe 's/??/oo/i' <<< "F??" # -> "Foo"
-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 codeas 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
-C
打开对流和文件的 UTF-8 支持,假设当前语言环境是基于 UTF-8 的。-Mutf8
告诉 Perl 将源代码解释为 UTF-8(在这种情况下,传递给 的字符串-pe
) - 这是更冗长的较短等价物-e 'use utf8;'.
谢谢,马克里德
(Note that using awk
is not an option either, as awk
on macOS (i.e., BWK awk, a.k.a. BSD awk) appears to be completely unaware of locales altogether - its tolower()
and toupper()
functions ignore foreign characters (and sub()
/ gsub()
don't have case-insensitivity flags to begin with).)
(请注意,使用awk
也不是一个选项,因为awk
在 macOS(即BWK awk,又名BSD awk)上似乎完全不知道语言环境 - 它的tolower()
和toupper()
函数忽略外来字符(和sub()
/gsub()
没有不区分大小写的标志)首先)。)
回答by Wesley Rice
Editor's note: This solution doesn't work on macOS (out of the box), because it only applies to GNUsed
, whereas macOS comes with BSDsed
.
编者注:此解决方案不适用于 macOS(开箱即用),因为它仅适用于GNUsed
,而 macOS 带有BSDsed
。
Capitalize the 'I'.
大写“我”。
sed 's/foo/bar/I' file
回答by Wesley Rice
Another work-around for sed
on Mac OS X is to install gsed
from MacPorts or HomeBrew and then create the alias sed='gsed'
.
sed
Mac OS X 上的另一个解决方法是gsed
从 MacPorts 或 HomeBrew安装,然后创建别名sed='gsed'
.
回答by Benjamin W.
The sed FAQaddresses 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.
该sed的FAQ地址密切相关的不区分大小写的搜索。它指出 a) 许多版本的 sed 都支持它的标志 b) 在 sed 中这样做很尴尬,您应该使用 awk 或 Perl。
But to do it in POSIX sed, they suggest three options (adapted for substitution here):
但是要在 POSIX sed 中做到这一点,他们建议了三个选项(适用于此处的替换):
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 bys/FOO/bar/;s/[Ff]oo/bar/
To search for all possible matches, one can use bracket expressions for each character:
s/[Ff][Oo][Oo]/bar/
转换为大写并将原始行存储在保持空间中;但是,这不适用于替换,因为原始内容将在打印之前恢复,因此它仅适用于基于不区分大小写的匹配插入或添加行。
也许可能性仅限于
FOO
,Foo
和foo
。这些可以覆盖s/FOO/bar/;s/[Ff]oo/bar/
要搜索所有可能的匹配项,可以对每个字符使用括号表达式:
s/[Ff][Oo][Oo]/bar/
回答by user1307434
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 of sed
:
Mac 版本sed
似乎有点限制。解决此问题的一种方法是使用具有以下可用版本的 linux 容器(通过 Docker)sed
:
cat your_file.txt | docker run -i busybox /bin/sed -r 's/[0-9]{4}/****/Ig'
回答by gojimmypi
I had a similar need, and came up with this:
我有类似的需求,并想出了这个:
this command to simply find all the files:
这个命令可以简单地找到所有文件:
grep -i -l -r foo ./*
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:
this 排除 this_shell.sh(如果您将命令放在名为this_shell.sh的脚本中),将输出发送到控制台以查看发生了什么,然后在找到的每个文件名上使用 sed 将文本 foo 替换为 bar :
grep -i -l -r --exclude "this_shell.sh" foo ./* | tee /dev/fd/2 | while read -r x; do sed -b -i 's/foo/bar/gi' "$x"; done
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)
我选择了这种方法,因为我不喜欢为未修改的文件更改所有时间戳。提供 grep 结果只允许查看带有目标文本的文件(因此也可能提高性能/速度)
be sure to backup your files & test before using. May not work in some environments for files with embedded spaces. (?)
请务必在使用前备份您的文件并进行测试。对于带有嵌入空格的文件,在某些环境中可能不起作用。(?)
回答by CBB
If you are doing pattern matching first, e.g.,
如果您首先进行模式匹配,例如,
/pattern/s/xx/yy/g
then you want to put the I
after the pattern:
然后你想把I
模式放在后面:
/pattern/Is/xx/yy/g
Example:
例子:
echo Fred | sed '/fred/Is//willma/g'
returns willma
; without the I
, it returns the string untouched (Fred
).
返回willma
;如果没有I
,它将返回未触及的字符串 ( Fred
)。