在Mac和Linux上以递归方式搜索和替换文本文件


127

在linux shell中,以下命令将递归搜索并将'this'的所有实例替换为'that'(我面前没有Linux shell,但应该这样做)。

find . -name "*.txt" -print | xargs sed -i 's/this/that/g'

OSX上的类似命令会是什么样?


应该迁移到apple.stackexchange.comlinux或所有开发人员都不够通用。
AlikElzin-kilaka '16

Answers:


246

OS X混合使用了BSD和GNU工具,因此最好始终检查文档(尽管我发现它less甚至不符合OS X手册页):

https://web.archive.org/web/20170808213955/https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/sed.1.html

sed将参数after -i作为备份的扩展名。提供空字符串(-i '')表示不进行备份。

应该执行以下操作:

LC_ALL=C find . -type f -name '*.txt' -exec sed -i '' s/this/that/ {} +

-type f只是个好习惯;如果给sed一个目录,sed会抱怨。 -exec优先于xargs; 您无需理会-print0或任何事情。将{} +在年底意味着find将所有结果作为参数添加的,而不是给被叫命令的一个实例,再运行它为每个结果。(一个例外是当操作系统允许的最大命令行参数数被破坏时;在这种情况下,find它将运行多个实例。)


2
我在此替换中的“ this”包含一个正斜杠(localhost / site)-我正在替换.html文件中的URL的一部分....如何进行这样的替换。我尝试用双引号引起来,但失败了。
蒂莫西T.

6
sed语法允许使用几乎所有字符代替斜杠,例如,您可以使用%字符:sed "s%localhost/site%blah/blah%"。另一种选择是反斜杠转义分隔符:sed "s/localhost\/site/blah\/blah/"
TaylanUB

谢谢,让我尝试一下。但是,我确实尝试使用{}来分隔斜线,但仍然出现错误...
TimothyT。

16
还有其他人illegal byte sequence出错吗?如果是这样,请尝试:LC_ALL=C find . -type f -name '*.txt' -exec sed -i '' s/this/that/ {} +,它对我有用。
ColdTuna

10
这将仅替换每个文件一个事件,/g用于多个事件,例如LC_ALL=C find . -type f -exec sed -i '' s/search/replace/g {} +
jamesjara

152

对于Mac,更类似的方法是:

find . -name '*.txt' -print0 | xargs -0 sed -i "" "s/form/forms/g"

10
我希望我每次回来使用它时都可以投票赞成。到现在是15点,很简单。
Droogans,2015年

由于某种原因,它对我不起作用。它什么也没做。我在form360文件夹中,并且尝试将所有名称为easyform的字符串实例更改为form360,我正在运行以下命令:find . -name '*.php' -print0 | xargs -0 sed -i "" "s/easyform/form360/g"
Andres Ramos

2
对我来说,这应该是正确的答案。这是唯一为我工作的人。
nosequeldeebee

1
-print0 | 当文件名包含空格时,xargs -0在我的Mac上不起作用。
user2807219 '17

1
sed:。:就地编辑仅适用于常规文件
codeslapper


14

在Mac OSX 10.11.5上可以正常工作:

grep -rli 'old-word' * | xargs -I@ sed -i '' 's/old-word/new-word/g' @

xargs -I @ sed -i'''s / old-word / new-word / g'@在尝试了许多其他非工作建议后为我工作。谢谢!
DrB

13

以上在OSX上均不起作用。

请执行下列操作:

perl -pi -w -e 's/SEARCH_FOR/REPLACE_WITH/g;' *.txt

1
如果SEARCH_FOR和REPLACE_WITH是路径,如何转义'/'?
rraallvv

使用其他定界符。如果使用路径,则冒号或竖线将起作用。例如,“ s | SEARCH | REPLACE | g”。我们使用大括号,如“ s {SEARCH} {REPLACE}”中所示。
dannysauer

1
dito问题,在Mac上尝试不行-但似乎会产生错误?例如,我的路径被解释为文件?-bash:localhost / nohost:没有这样的文件或目录
Timothy T.

这不会深入文件夹。只有一级。
谢尔盖·罗曼诺夫

有关此命令的更多信息,请阅读此lifehacker.com/5810026/…–
kuzdu

7

在Linux和Mac OS X上均可使用的版本(通过将-e开关添加到sed):

export LC_CTYPE=C LANG=C
find . -name '*.txt' -print0 | xargs -0 sed -i -e 's/this/that/g'

我必须从此答案中进行导出,再从已接受的答案中进行导出(我不希望生成备份文件)
Lance 2014年

2
要解决“非法字节序列”错误,请在运行命令之前尝试设置LOCALE: export LC_CTYPE=C && export LANG=C
cjoy

如果您使用的是Git,请不要像我一样使用'*'而不是'* .filetype'来运行它。或者,您可以告别所有未发表的作品。
谢尔盖(Sergey)2016年

1
sed命令的mac版本在-i之后需要一个”,因此此答案是不正确的
G Huxley,

2

每当我键入此命令时,我似乎总会把它弄糊涂了,或者忘记了一个标志。我基于TaylanUB的答案在github上创建了一个Gist,该答案从当前目录中进行全局查找替换。这是Mac OSX特有的。

https://gist.github.com/nateflink/9056302

很好,因为现在我只是弹出一个终端,然后复制到:

curl -s https://gist.github.com/nateflink/9056302/raw/findreplaceosx.sh | bash -s“ find-a-url.com”“替换-a-url.com”

您可能会遇到一些奇怪的字节序列错误,所以这是完整的代码:

#!/bin/bash
#By Nate Flink

#Invoke on the terminal like this
#curl -s https://gist.github.com/nateflink/9056302/raw/findreplaceosx.sh | bash -s "find-a-url.com" "replace-a-url.com"

if [ -z "$1" ] || [ -z "$2" ]; then
  echo "Usage: ./$0 [find string] [replace string]"
  exit 1
fi

FIND=$1
REPLACE=$2

#needed for byte sequence error in ascii to utf conversion on OSX
export LC_CTYPE=C;
export LANG=C;

#sed -i "" is needed by the osx version of sed (instead of sed -i)
find . -type f -exec sed -i "" "s|${FIND}|${REPLACE}|g" {} +
exit 0

2

这是我可行的。在Mac OS X 10.10.4上

grep -e 'this' -rl . | xargs sed -i '' 's/this/that/g'

上面使用find的将更改不包含搜索文本的文件(在文件末尾添加新行),这很冗长。


2

如果您使用的是zsh终端,则可以使用通配符魔术:

sed -i "" "s/search/high-replace/g" *.txt


1

我使用了这种格式-但是...我发现我必须运行它三次或多次才能使其真正更改每个我发现极为奇怪的实例。运行一次将更改每个文件中的某些内容,但不是全部。两次运行完全相同的字符串将捕获所有实例。

find . -type f -name '*.txt' -exec sed -i '' s/thistext/newtext/ {} +

您需要多次运行此命令,您的sed正则表达式最后需要a / b g,否则它将仅替换thistext一行中的第一个匹配项。因此,您的正则表达式应为s/thistext/newtext/g
Les Nightingill

0

https://bitbucket.org/masonicboom/serp是一个go实用程序(即跨平台),已在OSX上进行了测试,可对给定目录中的文件中的文本进行递归搜索和替换,并确认每次替换。它是新的,所以可能是越野车。

用法如下:

$ ls test
a  d  d2 z
$ cat test/z
hi
$ ./serp --root test --search hi --replace bye --pattern "*"                         
test/z: replace hi with bye? (y/[n]) y
$ cat test/z
bye

0
find . -type f | xargs sed -i '' 's/string1/string2/g'

请参阅此处以获取更多信息。


-3

OSX上的命令应与漂亮用户界面下的Unix完全相同。


我想了很多,但没有。进给sed时,它会在文件前放置./,因此sed抱怨“无效的命令代码”。也许我只是累了;-)
杰克

@JacobusR,请从OSX终端剪切并粘贴-您必须输入略有不同的内容。
glenn jackman 2012年

3
你可能想-print0加入到find标志和-0xargs标志。
2012年

您也可以只使用-exec sed -i s/this/that/g {} \+代替-printand xargs
玛丽安

@JacobusR-即使有一个领先的“ ./”路径名,它也可以工作。但是,如果文件名中有空格,例如“ ./jacobus \ R.txt”,则使用时xargs可能会将以空格分隔的“ ./jacobus”作为要传递给的文件sed,然后使用“ R.txt” ,都不存在。
布雷特·黑尔

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.