我需要替换一个文件夹中的许多文件中的字符串,只有ssh访问服务器。我该怎么做呢?


当前回答

我使用ag, the_silver_searcher:

ag -0 -l 'old' | xargs -0 sed -ri.bak -e 's/old/new/g';

然后git清除。bak文件(rm在git rebase exec中运行时出现bug)

git clean -f '**/*.bak';

其他回答

为了维护我个人的英文节点,我写了一个实用程序脚本,帮助替换多对旧/新字符串,递归为一个目录下的所有文件。

新/旧字符串的多个对在一个散列映射中进行管理。

dir可以通过命令行或环境变量设置,映射是硬编码在脚本中,但如果需要,您可以修改代码从文件加载。

由于一些新特性,它需要bash 4.2。

en_standardize.sh:

#! /bin/bash
# (need bash 4.2+,)
# 
# Standardize phonetic symbol of English.
# 
# format:
#   en_standardize.sh [<dir>]
# 
# params:
# * dir
#   target dir, optional,
#   if not specified then use environment variable "$node_dir_en",
#   if both not provided, then will not execute,
# * 
# 

paramCount=$#

# figure target dir,
if [ $paramCount -ge 1 ]; then # dir specified
    echo -e "dir specified (in command):\n\t$1\n"
    targetDir=$1
elif [[ -v node_dir_en ]]; then # environable set,
    echo -e "dir specified (in environment vairable):\n\t$node_dir_en\n"
    targetDir=$node_dir_en
else # environable not set,
    echo "dir not specified, won't execute"
    exit
fi

# check whether dir exists,
if [ -d $targetDir ]; then
    cd $targetDir
else
    echo -e "invalid dir location:\n\t$targetDir\n"
    exit
fi

# initial map,
declare -A itemMap
itemMap=( ["ɪ"]="i" ["ː"]=":" ["ɜ"]="ə" ["ɒ"]="ɔ" ["ʊ"]="u" ["ɛ"]="e")

# print item maps,
echo 'maps:'
for key in "${!itemMap[@]}"; do
    echo -e "\t$key\t->\t${itemMap[$key]}"
done
echo -e '\n'

# do replace,
for key in "${!itemMap[@]}"; do
    grep -rli "$key" * | xargs -i@ sed -i "s/$key/${itemMap[$key]}/g" @
done

echo -e "\nDone."
exit

当使用-i开关调用时,流编辑器确实会“inplace”修改多个文件,该开关以备份文件结尾作为参数。所以

sed -i.bak 's/foo/bar/g' *

在此文件夹中的所有文件中,将foo替换为bar,但不会下降到子文件夹中。但是,这将为目录中的每个文件生成一个新的.bak文件。 要递归地为该目录及其所有子目录中的所有文件执行此操作,您需要一个助手(如find)来遍历目录树。

find ./ -print0 | xargs -0 sed -i.bak 's/foo/bar/g' *

Find允许您进一步限制要修改的文件,通过指定进一步的参数,如Find ./ -name '*.php' -或name '*.html' -print0(如有必要)。


注意:GNU sed不需要文件结尾,sed -i 's/foo/bar/g' *也可以;FreeBSD sed要求扩展,但允许中间有一个空格,因此sed -i .bak s/foo/bar/g *可以工作。

如果文件包含反斜杠(通常是路径),你可以尝试这样做:

sed -i -- 's,<path1>,<path2>,g' *

ex:

sed -i -- 's,/foo/bar,/new/foo/bar,g' *.sh (in all shell scripts available)

第一行出现的“foo”将被替换为“bar”。你可以用第二行来检查。

grep -rl 'foo' . | xargs sed -i 's/foo/bar/g'
grep 'foo' -r * | awk -F: {'print $1'} | sort -n | uniq -c

在我发现这个问题(和答案)之前,我确实编造了自己的解决方案。 我搜索了“replace”、“few”和“xml”的不同组合,因为那是我的应用程序,但没有找到这个特定的组合。

我的问题:我有spring xml文件,其中包含测试用例的数据,其中包含复杂的对象。java源代码上的重构改变了许多类,但不适用于xml数据文件。为了保存测试用例数据,我需要更改所有xml文件中的所有类名,这些文件分布在几个目录中。同时保存原始xml文件的备份副本(尽管这不是必须的,因为版本控制可以在这里保存我)。

我正在寻找find + sed的某种组合,因为它在其他情况下也适用,但不能同时使用几个替换。

然后我找到了ask ubuntu response,它帮助我构建了我的命令行:

find -name "*.xml" -exec sed -s --in-place=.bak -e 's/firstWord/newFirstWord/g;s/secondWord/newSecondWord/g;s/thirdWord/newThirdWord/g' {} \;

而且效果非常好(好吧,我的箱子有六种不同的替代品)。但请注意,它将触及当前目录下的所有*.xml文件。正因为如此,如果你要对版本控制系统负责,你可能想要先进行过滤,只将那些实际拥有你想要的字符串传递给sed;如:

find -name "*.xml" -exec grep -e "firstWord" -e "secondWord" -e "thirdWord" {} \; -exec sed -s --in-place=.bak -e 's/firstWord/newFirstWord/g;s/secondWord/newSecondWord/g;s/thirdWord/newThirdWord/g' {} \;