如何从命令行执行递归查找和替换?

如何从命令行执行递归查找和替换?

使用 bash 或 zshell 之类的 shell,如何进行递归“查找和替换”?换句话说,我想将此目录及其子目录中的所有文件中的每个“foo”替换为“bar”。

答案1

此命令可以完成此操作(已在 Mac OS X Lion 和 Kubuntu Linux 上测试)。

# Recursively find and replace in files
find . -type f -name "*.txt" -print0 | xargs -0 sed -i '' -e 's/foo/bar/g'

工作原理如下:

  1. find . -type f -name '*.txt'在当前目录 ( .) 及以下目录中查找-type f名称以 结尾的所有常规文件 ( ).txt
  2. |将该命令的输出(文件名列表)传递给下一个命令
  3. xargs收集这些文件名并将它们逐一交给sed
  4. sed -i '' -e 's/foo/bar/g'表示“在不备份的情况下就地编辑文件,并s/foo/bar在每行多次进行以下替换( /g)”(参见man sed

请注意,第 4 行中的“没有备份”部分对我来说是可以的,因为我更改的文件无论如何都在版本控制之下,所以如果出现错误,我可以轻松撤消。

为了避免记住这一点,我使用交互式 bash 脚本,如下所示:

#!/bin/bash
# find_and_replace.sh

echo "Find and replace in current directory!"
echo "File pattern to look for? (eg '*.txt')"
read filepattern
echo "Existing string?"
read existing
echo "Replacement string?"
read replacement
echo "Replacing all occurences of $existing with $replacement in files matching $filepattern"

find . -type f -name $filepattern -print0 | xargs -0 sed -i '' -e "s/$existing/$replacement/g"

答案2

find . -type f -name "*.txt" -exec sed -i'' -e 's/foo/bar/g' {} +

这将消除xargs依赖性。

答案3

如果你使用 Git,那么你可以这样做:

git grep -lz foo | xargs -0 sed -i '' -e 's/foo/bar/g'

-l仅列出文件名。-z在每个结果后打印一个空字节。

我最终这样做是因为项目中的某些文件在文件末尾没有换行符,而 sed 即使没有进行其他更改也会添加换行符。(对于文件末尾是否应该有换行符,没有评论。

答案4

这是我为此使用的 zsh/perl 函数:

change () {
        from=$1 
        shift
        to=$1 
        shift
        for file in $*
        do
                perl -i.bak -p -e "s{$from}{$to}g;" $file
                echo "Changing $from to $to in $file"
        done
}

我会使用

$ change foo bar **/*.java

(例如)

相关内容