首页 文章

如何用awk或sed进行递归查找/替换字符串?

提问于
浏览
558

如何找到并替换每次出现的事件:

subdomainA.example.com

subdomainB.example.com

在递送的 /home/www/ 目录树下的每个文本文件中?

30 回答

  • 2

    如果你想在不完全破坏你的SVN存储库的情况下使用它,你可以通过这样做来告诉'find'忽略所有隐藏文件:

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

    我只是需要这个并且对可用示例的速度不满意 . 所以我想出了自己的:

    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万个文件,而其他文件花费了很长时间,我不能等到它们完成 .

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

    例如,'s a version that should be more general than most; it doesn' t需要 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'
    
  • 2

    Note :不要在包含git repo的文件夹上运行此命令 - 更改为.git可能会损坏您的git索引 .

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

    与此处的其他答案相比,这比大多数答案更简单,并使用sed而不是perl,这是原始问题所要求的 .

  • 1

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

  • 11

    试试这个:

    sed -i 's/subdomainA/subdomainB/g' `grep -ril 'subdomainA' *`
    
  • 218

    我只是使用上衣:

    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>)"
    
  • 1
    #!/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
    
  • 1

    要将文件减少到递归 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
    
  • 12

    对我来说,最容易记住的解决方案是https://stackoverflow.com/a/2113224/565525,即:

    sed -i '' -e 's/subdomainA/subdomainB/g' $(find /home/www/ -type f)
    

    NOTE-i '' 解决了OSX问题 sed: 1: "...": invalid command code .

    NOTE :如果要处理的文件太多,您将获得 Argument list too long . 解决方法 - 使用上述的 find -execxargs 解决方案 .

  • 7

    使用 grepsed 的组合

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

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

    希望对你有帮助 !!!

  • 2

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

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

    作为额外的一个漂亮的oneliner . 使用git grep .

    git grep -lz 'subdomainA.example.com' | xargs -0 perl -i'' -pE "s/subdomainA.example.com/subdomainB.example.com/g"
    
  • 3

    对于任何使用silver searcher的人( ag

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

    由于ag默认忽略git / hg / svn文件/文件夹,因此可以安全地在存储库中运行 .

  • 1

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

  • 15

    对我来说最简单的方法是

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

    所有技巧几乎都一样,但我喜欢这个:

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

    • -type f

    文件类型:常规文件

    • -exec command {} +

    -exec操作的此变体在所选文件上运行指定的命令,但命令行是通过在末尾附加每个选定的文件名来构建的;命令的调用总数将远远少于匹配文件的数量 . 命令行的构建方式与xargs构建命令行的方式大致相同 . 命令中只允许一个“{}”实例 . 该命令在起始目录中执行 .

  • 731

    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 允许您在实际执行之前查看将更改的文件 .

  • 4

    根据this博客文章:

    find . -type f | xargs perl -pi -e 's/oldtext/newtext/g;'
    
  • 4

    如果您不介意将 vimgrepfind 工具一起使用,则可以在此链接中跟进用户Gert给出的答案 - > 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

  • 7

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

    qsh命令的局限性:

    • find没有-print0选项

    • xargs没有-0选项

    • sed没有-i选项

    Thus the solution in 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
    

    注意事项:

    • 解决方案排除错误处理

    • 不是由OP标记的Bash

  • 54

    要替换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 )可以分隔文件名,即使它们包含空格或诸如此类的东西 .

  • 0

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

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

    将获取目录中的所有文件并将 | 替换为名为“Perl pie”的x(简单的馅饼)

  • 1

    这是我为OSX和Windows(msys2)找到的最佳解决方案 . 应该可以使用任何可以获得sed的gnu版本的东西 . 跳过.git目录,这样就不会破坏你的校验和 .

    在mac上,首先安装coreutils并确保gsed在路径中 -

    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>
    
  • 0
    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 手册页:"The command line is built in much the same way that xargs builds its command lines."

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

  • 1

    A bit old school but this worked on OS X.

    几乎没有技巧:

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

    •必须对 . 进行转义以确保 sed 不将它们评估为"any character"

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

    另请注意,这是编辑一个Jinja模板以在 import 的路径中传递 variable (但这是偏离主题的) .

    First, verify your sed command does what you want (this will only print the changes to stdout, it will not change the files):

    for file in $(find . -name *.sls -type f); do echo -e "\n$file: "; sed 's,foo\.bar,foo/bar/\"+baz+\"/,g' $file; done
    

    Edit the sed command as needed, once you are ready to make changes:

    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的评论中所述) .

    快乐的人们!

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

    只是为了避免改变

    • 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' {} \;
    

相关问题