如何找到并替换每次出现的事件:
subdomainA.example.com
带
subdomainB.example.com
在/home/www/
目录树下的每个文本文件中递归?
答案 0 :(得分:782)
注意:不要在包含git repo的文件夹上运行此命令 - 更改为.git可能会损坏您的git索引。
find /home/www -type f -print0 | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'
来自man find
:
-print0 (仅限GNU
find
)告诉find
使用空字符(\0
)而不是空格作为找到的路径名之间的输出分隔符。如果您的文件可以包含空格或其他特殊字符,则这是一个更安全的选项。如果您使用-print0
或find
,则建议使用-exec <command>
参数xargs
-0
中需要xargs
参数。)
答案 1 :(得分:227)
注意:不要在包含git repo的文件夹上运行此命令 - 更改为.git可能会损坏您的git索引。
find /home/www/ -type f -exec \
sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +
与其他答案相比,这比大多数答案简单,并使用sed而不是perl,这是原始问题所要求的。
答案 2 :(得分:141)
最简单的方法是
grep -rl oldtext . | xargs sed -i 's/oldtext/newtext/g'
答案 3 :(得分:56)
所有技巧几乎相同,但我喜欢这个:
find <mydir> -type f -exec sed -i 's/<string1>/<string2>/g' {} +
find <mydir>
:在目录中查找。
-type f
:
文件类型为:常规文件
-exec command {} +
:
-exec操作的此变体在所选文件上运行指定的命令,但命令行是通过追加来构建的 每个选定的文件名末尾;命令的调用总数将远远少于该数量 匹配的文件。命令行的构建方式与xargs构建命令行的方式大致相同。只有一个实例 命令中允许使用`{}'。该命令在起始目录中执行。
答案 4 :(得分:39)
cd /home/www && find . -type f -print0 |
xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'
答案 5 :(得分:29)
对我而言,最容易记住的解决方案是https://stackoverflow.com/a/2113224/565525,即:
sed -i '' -e 's/subdomainA/subdomainB/g' $(find /home/www/ -type f)
注意:-i ''
解决了OSX问题sed: 1: "...": invalid command code .
注意:如果有太多文件需要处理,则会获得Argument list too long
。解决方法 - 使用上述find -exec
或xargs
解决方案。
答案 6 :(得分:24)
对于使用silver searcher(ag
)
ag SearchString -l0 | xargs -0 sed -i 's/SearchString/Replacement/g'
由于ag默认忽略git / hg / svn文件/文件夹,因此可以安全地在存储库中运行。
答案 7 :(得分:15)
要将文件减少到递归sed
,您可以grep
为您的字符串实例:
grep -rl <oldstring> /path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g
如果您运行man grep
,您会注意到如果您想省略搜索.git目录,也可以定义--exlude-dir="*.git"
标志,避免git索引问题,正如其他人礼貌地指出的那样。
引导您:
grep -rl --exclude-dir="*.git" <oldstring> /path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g
答案 8 :(得分:14)
一个好的oneliner作为额外的。使用git grep。
git grep -lz 'subdomainA.example.com' | xargs -0 perl -i'' -pE "s/subdomainA.example.com/subdomainB.example.com/g"
答案 9 :(得分:11)
这个与git存储库兼容,有点简单:
Linux的:
git grep -l 'original_text' | xargs sed -i 's/original_text/new_text/g'
的Mac:
git grep -l 'original_text' | xargs sed -i '' -e 's/original_text/new_text/g'
(感谢http://blog.jasonmeridth.com/posts/use-git-grep-to-replace-strings-in-files-in-your-git-repository/)
答案 10 :(得分:8)
find /home/www/ -type f -exec perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +
find /home/www/ -type f
将列出/ home / www /(及其子目录)中的所有文件。
“-exec”标志告诉find对找到的每个文件运行以下命令。
perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +
是对文件运行的命令(一次多个)。 {}
被文件名替换。
命令末尾的+
告诉find
为许多文件名构建一个命令。
根据find
手册页:
“命令行的构建方式大致相同
xargs构建了命令行。“
因此,可以在不使用xargs -0
或-print0
的情况下实现目标(并处理包含空格的文件名)。
答案 11 :(得分:7)
我只是需要这个并且对可用示例的速度不满意。所以我提出了自己的想法:
cd /var/www && ack-grep -l --print0 subdomainA.example.com | xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'
Ack-grep在查找相关文件方面非常有效。这个命令轻而易举地取代了~14.5万个文件,而其他文件花费了很长时间,我不能等到它们完成。
答案 12 :(得分:6)
或使用快速的GNU Parallel:
grep -rl oldtext . | parallel sed -i 's/oldtext/newtext/g' {}
答案 13 :(得分:4)
grep -lr 'subdomainA.example.com' | while read file; do sed -i "s/subdomainA.example.com/subdomainB.example.com/g" "$file"; done
我想大多数人都不知道他们可以将某些东西输入“while read file”中,并且它避免了那些令人讨厌的-print0 args,同时预先设置了文件名中的空格。
在sed之前进一步添加echo
可以让您在实际执行之前查看哪些文件会发生变化。
答案 14 :(得分:4)
试试这个:
sed -i 's/subdomainA/subdomainB/g' `grep -ril 'subdomainA' *`
答案 15 :(得分:4)
您可以使用awk解决此问题,如下所示,
for file in `find /home/www -type f`
do
awk '{gsub(/subdomainA.example.com/,"subdomainB.example.com"); print $0;}' $file > ./tempFile && mv ./tempFile $file;
done
希望这会对你有帮助!!!
答案 16 :(得分:3)
#!/usr/local/bin/bash -x
find * /home/www -type f | while read files
do
sedtest=$(sed -n '/^/,/$/p' "${files}" | sed -n '/subdomainA/p')
if [ "${sedtest}" ]
then
sed s'/subdomainA/subdomainB/'g "${files}" > "${files}".tmp
mv "${files}".tmp "${files}"
fi
done
答案 17 :(得分:2)
有点旧学但这适用于OS X.
几乎没有技巧:
•仅编辑当前目录
下扩展名为.sls
的文件
•必须对.
进行转义,以确保sed
不会将其评估为“任何字符”
•,
用作sed
分隔符,而不是通常的/
另请注意,这是编辑一个Jinja模板,以便在variable
的路径中传递import
(但这不是主题)。
首先,验证您的sed命令是否符合要求(这只会将更改打印到stdout,它不会更改文件):
for file in $(find . -name *.sls -type f); do echo -e "\n$file: "; sed 's,foo\.bar,foo/bar/\"+baz+\"/,g' $file; done
准备好进行更改后,根据需要编辑sed命令:
for file in $(find . -name *.sls -type f); do echo -e "\n$file: "; sed -i '' 's,foo\.bar,foo/bar/\"+baz+\"/,g' $file; done
请注意 sed 命令中的-i ''
,我不想创建原始文件的备份(如In-place edits with sed on OS X或Robert Lujo在此评论中所述页)。
快乐的人们!
答案 18 :(得分:2)
这里的版本应该比大多数版本更通用;例如,它不需要find
(改为使用du
)。它确实需要xargs
,只有在某些Plan 9版本(例如9front)中才能找到。
du -a | awk -F' ' '{ print $2 }' | xargs sed -i -e 's/subdomainA\.example\.com/subdomainB.example.com/g'
如果要添加文件扩展名之类的过滤器,请使用grep
:
du -a | grep "\.scala$" | awk -F' ' '{ print $2 }' | xargs sed -i -e 's/subdomainA\.example\.com/subdomainB.example.com/g'
答案 19 :(得分:2)
我只是使用上衣:
find . -name '*.[c|cc|cp|cpp|m|mm|h]' -print0 | xargs -0 tops -verbose replace "verify_noerr(<b args>)" with "__Verify_noErr(<args>)" \
replace "check(<b args>)" with "__Check(<args>)"
答案 20 :(得分:2)
According to this blog post:
find . -type f | xargs perl -pi -e 's/oldtext/newtext/g;'
答案 21 :(得分:2)
只是为了避免改变
但仍然
(可能在域根背后的想法不太好)
find /home/www/ -type f -exec sed -i 's/\bsubdomainA\.example\.com\b/\1subdomainB.example.com\2/g' {} \;
答案 22 :(得分:2)
最简单的替换方式(所有文件,目录,递归)
find . -type f -not -path '*/\.*' -exec sed -i 's/foo/bar/g' {} +
注意:有时,您可能需要忽略一些隐藏文件,例如.git
。
如果要包括隐藏文件的使用,
find . -type f -exec sed -i 's/foo/bar/g' {} +
在两种情况下,字符串foo
都将被新的字符串bar
取代
答案 23 :(得分:2)
如果您不介意将vim
与grep
或find
工具一起使用,则可以在此链接中跟进用户Gert给出的答案 - &gt; How to do a text replacement in a big folder hierarchy?
这是这笔交易:
以递归方式grep查找要在特定路径中替换的字符串,并仅获取匹配文件的完整路径。 (那将是$(grep 'string' 'pathname' -Rl)
。
(可选)如果您想在集中目录中对这些文件进行预备,也可以使用它:cp -iv $(grep 'string' 'pathname' -Rl) 'centralized-directory-pathname'
之后,您可以按照类似于给定链接上提供的方案,在vim
中随意编辑/替换:
:bufdo %s#string#replacement#gc | update
答案 24 :(得分:1)
如果您需要排除目录(--exclude-dir=.svn
)并且还可能具有带空格的文件名(将0Byte与{{1}一起使用) }和grep -Z
xargs -0
答案 25 :(得分:1)
要替换git存储库中的所有匹配项,您可以使用:
git ls-files -z | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'
有关列出存储库中所有文件的其他选项,请参阅List files in local git repo?。 -z
选项告诉git将文件名与零字节分开,这确保xargs
(带有选项-0
)可以分隔文件名,即使它们包含空格或诸如此类的东西。< / p>
答案 26 :(得分:1)
更改多个文件(并将备份保存为*.bak
):
perl -p -i -e "s/\|/x/g" *
将获取目录中的所有文件,并将|
替换为x
被称为“Perl馅饼”(简单的馅饼)
答案 27 :(得分:1)
perl -p -i -e 's/oldthing/new_thingy/g' `grep -ril oldthing *`
答案 28 :(得分:1)
对于IBMi上的Qshell(qsh),而不是由OP标记的bash。
qsh命令的限制:
因此qsh中的解决方案:
PATH='your/path/here'
SEARCH=\'subdomainA.example.com\'
REPLACE=\'subdomainB.example.com\'
for file in $( find ${PATH} -P -type f ); do
TEMP_FILE=${file}.${RANDOM}.temp_file
if [ ! -e ${TEMP_FILE} ]; then
touch -C 819 ${TEMP_FILE}
sed -e 's/'$SEARCH'/'$REPLACE'/g' \
< ${file} > ${TEMP_FILE}
mv ${TEMP_FILE} ${file}
fi
done
注意事项:
答案 29 :(得分:1)
使用grep
和sed
for pp in $(grep -Rl looking_for_string)
do
sed -i 's/looking_for_string/something_other/g' "${pp}"
done
答案 30 :(得分:1)
如果你想在不完全破坏你的SVN存储库的情况下使用它,你可以通过这样做来告诉'find'忽略所有隐藏文件:
find . \( ! -regex '.*/\..*' \) -type f -print0 | xargs -0 sed -i 's/subdomainA.example.com/subdomainB.example.com/g'
答案 31 :(得分:0)
更简单的方法是在命令行上使用以下内容
find /home/www/ -type f|xargs perl -pi -e 's/subdomainA\.example\.com/subdomainB.example.com/g'
答案 32 :(得分:0)
如果您有权访问节点,则可以执行npm install -g rexreplace
然后
rexreplace 'subdomainA.example.com' 'subdomainB.example.com' /home/www/**/*.*
答案 33 :(得分:0)
将所有与 string_1 匹配的内容替换为当前所有 .c 和 .h 文件的 string_2 目录和子目录(不包括.git /)。
适用于 Mac :
find . -type f -path "*.git*" -prune -o -name '*\.[ch]' -exec \
sed -i '' -e 's/'$1'/'$2'/g' {} +
这应该适用于 Linux (尚未测试):
find . -type f -path "*.git*" -prune -o -name '*\.[ch]' -exec \
sed -i 's/string_1/string_2/g' {} +
答案 34 :(得分:0)
这是我为OSX和Windows(msys2)找到的最佳解决方案。应该可以使用任何可以获得sed的gnu版本的东西。跳过.git目录,这样就不会破坏你的校验和。
在Mac上,只需先安装coreutils并确保gsed位于路径中 -
brew install coreutils
然后我将此功能粘贴在我的zshrc / bashrc - &gt;
中replace-recursive() {
hash gsed 2>/dev/null && local SED_CMD="gsed" || SED_CMD="sed"
find . -type f -name "*.*" -not -path "*/.git/*" -print0 | xargs -0 $SED_CMD -i "s/$1/$2/g"
}
usage: replace-recursive <find> <replace>