我如何查找和替换每次出现的情况:
subdomainA.example.com
与
subdomainB.example.com
在/home/www/
目录树下的每个文本文件中递归?
-path ./.git -prune -o
在find . -path ./.git -prune -o -type f -name '*matchThisText*' -print0
管道传递到xargs之前使用in 来从结果中排除目录(例如git)
我如何查找和替换每次出现的情况:
subdomainA.example.com
与
subdomainB.example.com
在/home/www/
目录树下的每个文本文件中递归?
-path ./.git -prune -o
在find . -path ./.git -prune -o -type f -name '*matchThisText*' -print0
管道传递到xargs之前使用in 来从结果中排除目录(例如git)
Answers:
find /home/www \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'
-print0
告诉您find
将每个结果打印为一个空字符,而不是换行。如果您的目录中的文件名称中带有换行符,这种情况极有可能发生,这仍然可以xargs
使用正确的文件名。
\( -type d -name .git -prune \)
是一个完全跳过名为的所有目录的表达式.git
。如果使用SVN或要保留其他文件夹,则可以轻松扩展它-只需与更多名称匹配即可。它大致等效于-not -path .git
,但效率更高,因为它不会检查目录中的每个文件,而是会完全跳过它。该-o
后则需要因为如何-prune
实际工作。
有关更多信息,请参见man find
。
sed: 1: "...": invalid command code .
问题。看来-i选项需要扩展并解析's/../...'
命令。解决方案:将扩展名''传递给-i选项,例如sed -i '' 's/...
。
svn st
显示任何更改,那是因为您还修改了.svn目录中的文件!使用find . -maxdepth 1 -type f -print0 | xargs -0 sed -i 's/toreplace/replaced/g'
代替。
grep -r 'hello' -l --null . | xargs -0 sed -i 's#hello#world#g'
可避免编辑不相关的文件(sed可能会更改文件编码)。
find .git ... | ... 'sed -i s/(the opposite from before)/g'
修复git索引
注意:不要在包含git repo的文件夹上运行此命令-更改.git可能会损坏git索引。
find /home/www/ -type f -exec \
sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +
与这里的其他答案相比,它比大多数答案更简单,并且使用sed代替了perl,这是原始问题的要求。
-i
选项提供一个明确的空字符串arg 。即: sed -i '' 's/original/replacement/g'
+
大大减少了sed
产生的进程数量。效率更高。
find . -not -path '*/\.git*' -type f ...
。
对我来说最简单的方法是
grep -rl oldtext . | xargs sed -i 's/oldtext/newtext/g'
-I
或--binary-file=without-match
grep标志。
.svn
。例如:grep -rl oldtext . --exclude-dir=.svn | xargs sed -i 's/oldtext/newtext/g'
brew install gnu-sed
并gsed
在OSX上使用以避免造成痛苦。
git grep -rl oldtext . | xargs sed -i 's/oldtext/newtext/g'
。它不是很好,在所有他妈的你的.git
DIR
所有的技巧都差不多,但是我喜欢这个技巧:
find <mydir> -type f -exec sed -i 's/<string1>/<string2>/g' {} +
find <mydir>
:在目录中查找。
-type f
:
文件类型:常规文件
-exec command {} +
:
-exec操作的此变体在选定的文件上运行指定的命令,但是通过在末尾附加每个选定的文件名来构建命令行。该命令的调用总数将远远少于匹配文件的数目。命令行的构建与xargs构建命令行的方式几乎相同。命令中仅允许使用一个{}实例。该命令在起始目录中执行。
file
命令尝试确定每个文件的类型,但是其输出中的随机变化可能会有些令人困惑。该-I
(又名--mime
)选项可以帮助一些,或者--mime-type
如果你有。遗憾的是,如何精确地重构此整洁的单代码来做到这一点,超出了这个小注释框的范围。如果您需要帮助,也许会发布一个单独的问题?(也许可以在此处添加带有链接的评论。)
cd /home/www && find . -type f -print0 |
xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'
-print0
和xargs
代替-exec
or -execdir
?
find -exec command {} +
-它确实避免了xargs之类的命令的过多调用,但是没有单独的过程。
find -exec ... {} +
自2006
对我而言,最容易记住的解决方案是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
解决方案。
workaround
应在所有情况下的首选语法。
$(find...)
在于,shell无法处理带有空格或其他shell元字符的文件名。如果您知道这不是问题,则可以使用这种方法。但是我们有太多问题要问,人们没有对此问题发出警告或不理解警告。
对于使用Silver Searcher(ag
)的任何人
ag SearchString -l0 | xargs -0 sed -i 's/SearchString/Replacement/g'
由于ag默认会忽略git / hg / svn文件/文件夹,因此可以安全地在存储库中运行。
一个不错的oneliner作为额外。使用git grep。
git grep -lz 'subdomainA.example.com' | xargs -0 perl -i'' -pE "s/subdomainA.example.com/subdomainB.example.com/g"
refactor() { echo "Replacing $1 by $2 in all files in this git repository." git grep -lz $1| xargs -0 perl -i'' -pE "s/$1/$2/g" }
用法,例如,将'word'替换为'sword':refactor word sword
然后使用验证其作用git diff
。
要减少要递归处理的文件sed
,可以grep
为您的字符串实例:
grep -rl <oldstring> /path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g
如果您运行该命令,man grep
则会发现--exlude-dir="*.git"
如果您不想在.git目录中进行搜索,则还可以定义一个标志,从而避免了git索引问题,就像其他人有礼貌地指出的那样。
引导您:
grep -rl --exclude-dir="*.git" <oldstring> /path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g
这与git仓库兼容,并且更简单:
Linux:
git grep -l 'original_text' | xargs sed -i 's/original_text/new_text/g'
苹果电脑:
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/)
git-grep
的-z
选项与一起使用xargs -0
。
git grep
显然只有在git
回购中才有意义。一般替换为grep -r
。
-z
,git-grep
将输出字段用空字节而不是换行符分隔;和with一起-0
,xargs
将读取由空字节分隔的输入,而不是空格(并且不要用引号引起奇怪的事情)。因此,如果您不希望命令在文件名包含空格,引号或其他有趣字符的情况下中断,则命令为:git grep -z -l 'original_text' | xargs -0 sed ...
。
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
。
我只需要这个,对可用示例的速度并不满意。所以我想出了自己的:
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在查找相关文件方面非常有效。这条命令轻而易举地替换了约145 000个文件,而其他命令却花了很长时间,我等不及要等到它们完成。
grep -ril 'subdomainA' *
还不及grep -Hr 'subdomainA' * | cut -d: -f1
。
最简单的替换方法(所有文件,目录,递归)
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
grep -lr 'subdomainA.example.com' | while read file; do sed -i "s/subdomainA.example.com/subdomainB.example.com/g" "$file"; done
我想大多数人都不知道他们可以将某些内容传送到“ while读取文件”中,并且避免了那些讨厌的-print0 args,同时保留了文件名中的空格。
echo
在sed之前进一步添加,可以让您在实际执行操作之前先查看将要更改的文件。
-print0
是有用的,因为它while read
可以处理根本无法处理的情况-换行符是Unix文件名中的有效字符,因此为了使代码完全健壮,它也需要处理此类文件名。(此外,您还要read -r
避免在其中出现一些令人讨厌的POSIX旧式行为read
。)
sed
如果没有匹配项,则该操作为空操作,因此这grep
并不是必须的;尽管对于避免重写不包含任何匹配项的文件(如果有很多匹配项)或希望避免不必要地更新文件上的日期戳,这是一种有用的优化方法。
您可以使用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
希望这能够帮到你 !!!
sed
当甚至使用osx特定设置包括二进制文件时,所有基于命令的命令都会失败。
尝试这个:
sed -i 's/subdomainA/subdomainB/g' `grep -ril 'subdomainA' *`
sed -i 's/subdomainA/subdomainB/g'
` grep -ril 'subdomainA' /home/www/*
`-这看起来仍然不太好,但是应该在复制粘贴中生存:)干杯!
如果您不介意vim
与grep
或find
工具一起使用,则可以跟踪用户Gert在此链接-> 如何在大文件夹层次结构中进行文本替换的答案。。
这是交易:
递归grep表示要在特定路径中替换的字符串,并且仅采用匹配文件的完整路径。(那是$(grep 'string' 'pathname' -Rl)
。
(可选)如果您要在集中目录中对这些文件进行预备份,则可以使用以下方法: cp -iv $(grep 'string' 'pathname' -Rl) 'centralized-directory-pathname'
之后,您可以vim
按照与给定链接上提供的方案类似的方案随意编辑/替换:
:bufdo %s#string#replacement#gc | update
有点老派了,但这在OS X上也能用。
技巧不多:
•仅编辑.sls
当前目录下具有扩展名的文件
• .
必须转义以确保sed
不会将其评估为“任何字符”
• ,
用作sed
分隔符,而不是通常的/
还要注意,这是编辑Jinja模板以variable
在的路径中传递a 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
请注意,-i ''
在sed命令中,我不想创建原始文件的备份(如OS X上sed的就地编辑中所述)在本页面或罗伯特·路约的评论)。
镇定快乐的人!
我只用上衣:
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>)"
这个版本应该比大多数版本更通用。例如,它不需要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'
对于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
注意事项:
for
。
如果您想在不完全破坏SVN存储库的情况下使用此功能,则可以通过执行以下操作来告诉'find'忽略所有隐藏文件:
find . \( ! -regex '.*/\..*' \) -type f -print0 | xargs -0 sed -i 's/subdomainA.example.com/subdomainB.example.com/g'
使用grep
和的组合sed
for pp in $(grep -Rl looking_for_string)
do
sed -i 's/looking_for_string/something_other/g' "${pp}"
done
grep -Rl pattern
生成的文件列表的输出在该模式所在的位置。文件不会for
循环读取。
for
循环;如果任何返回的文件名包含空格,则它将无法正常工作,因为shell会标记化for
参数列表。但是,然后在循环中使用不带引号的文件名变量,因此如果您对此进行修复,它将在此处中断。更正这些剩余的错误将使您的错误与@ MadMan2064的答案相同。
要替换git存储库中的所有匹配项,可以使用:
git ls-files -z | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'
请参阅在本地git repo中列出文件?其他选项以列出存储库中的所有文件。这些-z
选项告诉git用零字节分隔文件名,从而确保xargs
(使用选项-0
)可以分隔文件名,即使它们包含空格或其他也不可以。
更改多个文件(并将备份另存为*.bak
):
perl -p -i -e "s/\|/x/g" *
将获取目录中的所有文件,并|
用称为“ Perl pie”的x 替换(容易作为馅饼)