awk / sed:如何做一个string的recursion查找/replace?

如何查找和replace以下每个事件:

subdomainA.example.com 

 subdomainB.example.com 

/home/www/目录树(recursion查找/replace)下的每个文本文件中。

注意 :不要在包含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 only)告诉find使用空字符(\ 0)而不是空格作为find的path名之间的输出分隔符。 如果您的文件可以包含空格或其他特殊字符,这是一个更安全的选项。 build议使用-print0参数来查找是否使用-exec命令或xargs(在xargs中需要-0参数)。

注意 :不要在包含git repo的文件夹上运行这个命令 – 修改.git可能会破坏你的git索引。

 find /home/www/ -type f -exec \ sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g' {} + 

与其他答案相比,这比大多数简单,并使用sed,而不是perl,这是原来的问题要求。

所有的技巧都差不多,但我喜欢这个:

 find <mydir> -type f -exec sed -i 's/<string1>/<string2>/g' {} + 
  • find <mydir> :在目录中查找。

  • -type f

    文件是types:常规文件

  • -exec command {} +

    -exec操作的这种变体在选定的文件上运行指定的命令,但命令行是通过在每个选定的文件名后加上来构build的; 该命令的总调用次数将远远less于匹配文件的数量。 命令行的构build方式与xargs构build其命令行的方式大致相同。 命令中只允许有一个“{}”实例。 该命令在起始目录中执行。

 cd /home/www && find . -type f -print0 | xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' 

对我来说最简单的方法是

 grep -rl oldtext . | xargs sed -i 's/oldtext/newtext/g' 

对我来说,最简单的解决scheme是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 -execxargs解决scheme。

对于任何使用silverlightsearch者 ( ag

 ag SearchString -l0 | xargs -0 sed -i 's/SearchString/Replacement/g' 

由于默认情况下,g会忽略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" 

这个与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/

我只是需要这个,并不满意现有例子的速度。 所以我想出了我自己的:

 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在查找相关文件方面非常高效。 这个命令轻而易举地取代了大约145000个文件,而其他的则花了这么长时间,我不能等到它们完成。

 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在find的每个文件上运行以下命令。

 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' {} + 

是在文件上运行的命令(一次很多)。 {}被文件名取代。 命令末尾的+告诉find为许多文件名构build一个命令。

根据find手册页:“命令行的构build方式与xargs构build命令行的方式大致相同。

因此,可以在不使用xargs -0-print0的情况下实现目标(并处理包含空格的文件名)。

为了减less文件recursionsed通过,你可以grep你的string实例:

 grep -rl <oldstring> /path/to/folder | xargs sed -is^<oldstring>^<newstring>^g 

如果你运行man grep你会注意到你也可以定义一个--exlude-dir="*.git"标志,如果你想省略通过.git目录search,避免git索引问题,正如别人礼貌指出的那样。

引导您:

 grep -rl --exclude-dir="*.git" <oldstring> /path/to/folder | xargs sed -is^<oldstring>^<newstring>^g 

尝试这个:

 sed -i 's/subdomainA/subdomainB/g' `grep -ril 'subdomainA' *` 
 #!/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 

grep -lr 'subdomainA.example.com' | while read file; do sed -i "s/subdomainA.example.com/subdomainB.example.com/g" "$file"; done

我想大多数人不知道,他们可以pipe一些东西到“读取文件”,它避免了那些讨厌的-print0参数,而presevering空间的文件名。

在sed之前进一步添加echo ,可以让您在实际执行操作之前查看要更改的文件。

如果你不介意把vimgrep一起使用或者find工具,那么你可以在这个链接中跟踪由用户Gert给出的答案 – > 如何在大文件夹层次结构中进行文本replace? 。

这是交易:

  • recursion地grep你想要在特定path中replace的string,并且只取得匹配文件的完整path。 (这将是$(grep 'string' 'pathname' -Rl)

  • (可选)如果你想在集中式目录下做这些文件的预备份,也许你可以使用这个: cp -iv $(grep 'string' 'pathname' -Rl) 'centralized-directory-pathname'

  • 之后,你可以在vim按照类似于给出的链接提供的scheme编辑/replace:

    • :bufdo %s#string#replacement#gc | update

对于IBMi上的Qshell(qsh),不是由OP标记的bash。

qsh命令的局限性:

  • 找不到-print0选项
  • xargs没有-0选项
  • sed没有-i选项

因此qsh中的解决scheme:

  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 

注意事项:

  • 解决scheme不包括error handling
  • 不是由OP标记的Bash

如果你想在不完全破坏你的SVN仓库的情况下使用它,你可以通过下面的方法告诉'find'忽略所有隐藏的文件:

 find . \( ! -regex '.*/\..*' \) -type f -print0 | xargs -0 sed -i 's/subdomainA.example.com/subdomainB.example.com/g' 

使用grepsed组合

 for pp in $(grep -Rl looking_for_string) do sed -i 's/looking_for_string/something_other/g' "${pp}" done 

你可以使用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 

希望这会帮助你!

有点古老,但这在OS X上工作。

有几个诡计:

•只能在当前目录下编辑扩展名为.sls的文件

. 必须逃脱,以确保sed不评价他们为“任何性格”

•用作sed分隔符而不是常用的/

还要注意,这是编辑一个Jinja模板来传递一个variable在一个import的path(但这是closures主题)。

首先,validation你的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 '' ,我不想创build原始文件的备份(正如在OS X上就地编辑sed或Robert Lujo在此页面中的注释中所述)。

快乐的人们!

只是为了避免改变

  • NearlysubdomainA.example.com
  • subdomainA.example.comp.other

但仍然

  • subdomainA.example.com.IsIt.good

(也许不好在域根后面的想法)

 find /home/www/ -type f -exec sed -i 's/\bsubdomainA\.example\.com\b/\1subdomainB.example.com\2/g' {} \; 

更简单的方法是在命令行中使用下面的内容

 find /home/www/ -type f|xargs perl -pi -e 's/subdomainA\.example\.com/subdomainB.example.com/g' 

这是我发现的OSX和Windows(msys2)最好的解决scheme。 应该使用任何可以获得sed的GNU版本的东西。 跳过.git目录,这样不会破坏校验和。

在mac上,首先安装coreutils并确保gsed在path中 –

 brew install coreutils 

然后我坚持这个函数在我的zshrc / bashrc – >

 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> 

将所有匹配string_1的内容replace为当前目录和子目录(不包括.git /)中的所有.c.h文件的string_2

这适用于Mac

 find . -type f -path "*.git*" -prune -o -name '*\.[ch]' -exec \ sed -i '' -e 's/'$1'/'$2'/g' {} + 

这应该在Linux上工作(还没有testing过):

 find . -type f -path "*.git*" -prune -o -name '*\.[ch]' -exec \ sed -i 's/string_1/string_2/g' {} + 

如果你有访问节点,你可以做一个npm install -g rexreplace然后

 rexreplace 'subdomainA.example.com' 'subdomainB.example.com' /home/www/**/*.* 

为了replacegit仓库中的所有事件,你可以使用:

 git ls-files -z | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g' 

请参阅在本地git回购列表文件? 其他选项列出存储库中的所有文件。 -z选项告诉git使用零字节来分隔文件名,这可以确保xargs (带有选项-0 )可以分隔文件名,即使它们包含空格或不包含任何内容。

更改多个文件(并将备份保存为* .bak):

 perl -p -i -e "s/\|/x/g" * 

将所有目录下的文件replace为“|”,并用x称为“Perl pie”(很容易)

 perl -p -i -e 's/oldthing/new_thingy/g' `grep -ril oldthing *`