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

在 Linux shell 中,下面的命令将递归地搜索并用‘ that’替换所有‘ this’的实例(我面前没有 Linux shell,但它应该有)。

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

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

152636 次浏览

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 将 -i之后的参数作为备份的扩展名。

应采取以下措施:

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

-type f只是一个很好的实践; 如果您给它一个目录左右,sed 就会抱怨。

-exec优于 xargs; 您不必为 -print0或任何东西操心。

最后的 {} +意味着 find将把所有结果作为参数附加到被调用命令的一个实例,而不是为每个结果重新运行它。(一个例外是当操作系统允许的最大命令行参数数目被破坏时; 在这种情况下,find将运行多个实例。)

如果您得到一个类似于“无效字节序列”的错误,那么通过在命令开始处添加 LC_ALL=C来强制使用标准语言环境可能会有所帮助,如下所示:

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

以上这些都不能在 OSX 上工作。

做以下事情:

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

对于 Mac 来说,一个更为类似的方法是这样的:

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

作为一个替代解决方案,我在 MacOSX10.7.5上使用这个解决方案

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

提供者: Todd Cesere 的回答

无论何时我输入这个命令,我似乎总是把它弄乱,或者忘记了一个标志。我在 github 上根据 TaylanUB 的回答创建了一个 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”“ replace-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

一个同时适用于 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'

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

这是我在 Mac OS X 10.10.4上可用的一个

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

上面的使用 找到将更改不包含搜索文本的文件(在文件末尾添加一行新内容) ,这是冗长的。

如果你使用 zsh 终端,你可以使用通配符魔术:

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

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

更多信息请参考 给你

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

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

二零二一年

对我有效的方法是:

LC_ALL=C && LANG=C && find . -type f | xargs sed -i '' 's/old/new/g'

对于 都有 macOS 和 Linux:

我不确定其他的答案是否涉及 都有 Linux 和 macOS。如果有人这样做,也许我们可以编辑他们,使这一点明确。

下面是我为了针对 都有平台而使用的方法。

假设我们要对其执行查找/替换操作的文件包含以下文本:

Txt:

\{\{FROM}} hello world

这是剧本 替换 bash:

    #!/bin/bash
PATTERN="s/\{\{FROM}}/HELLOWORLD/"
if [[ `uname -s`" == "Darwin" ]]; then
sed -i '' "$PATTERN" file.txt
echo Darwin
else
sed -i "$PATTERN" file.txt
echo Linuxxxx
fi

后来我发现,在 sh 和 bash 之间使用单个括号和单个等于号可以更好地协作:

Replace.sh:

    PATTERN="s/\{\{FROM}}/HELLOWORLD/"
if [ `uname -s` = "Darwin" ]; then
sed -i '' "$PATTERN" file.txt
echo Darwin
else
sed -i "$PATTERN" file.txt
echo Linuxxxx
fi

你自己的跨平台系统:

我可以看到有人可以用 $1替换 $PATTERN,用 $2替换 file.txt,并且实际上能够围绕 sed 创建一个在两个平台上都可以工作的包装器,例如:

教育局常任秘书长 :

    PATTERN="$1"
FILE=$2
if [ `uname -s` = "Darwin" ]; then
sed -i '' "$PATTERN" $FILE
else
sed -i "$PATTERN" $FILE
fi
$ chmod 755 ssed
$ ./ssed 's/\{\{FROM}}/jameswashere/' file

然后文件将包含:

jameswashere hello world

那么递归查找/替换呢?

现在我们有了自己的独立于平台的 sed 包装器,我们可以使用它和 find 一起遍历子目录,并对匹配的文件执行 find/place:

$ find . -name "file" -exec ./ssed 's/\{\{FROM}}/that/g' {} \;

这招在 Mac 上很管用

LC_ALL=C && LANG=C && find . -type f | xargs sed -i '' 's/OLD_STRING/NEW_STRING/g'

但是指定我需要搜索/替换的文件类型要快得多

LC_ALL=C && LANG=C && find . -type f -name '*.html' | xargs sed -i '' 's/OLD_STRING/NEW_STRING/g'

在搜索/替换 urls 时,必须在斜杠之前加上反斜杠(\)

LC_ALL=C && LANG=C && find . -type f -name '*.html' | xargs sed -i '' 's/https:\/\/yahoo.com/https:\/\/google.com/g'