【问题标题】:Safe search&replace on linuxlinux上的安全搜索和替换
【发布时间】:2014-06-24 02:01:42
【问题描述】:

假设我的文件位于不同的子文件夹中,我想在这些文件中搜索、测试和替换某些内容。

我想分三步完成:

  1. 搜索特定模式(带或不带正则表达式)
  2. 测试用某些东西替换它(带或不带正则表达式)
  3. 仅将更改应用于相关文件

我目前的解决方案是在我的.bashrc 中定义一些别名,以便轻松使用grepsed

alias findsrc='find . -name "*.[ch]" -or -name "*.asm" -or -name "*.inc"'
alias grepsrc='findsrc | xargs grep -n --color '
alias sedsrc='findsrc | xargs sed '

那我用

  1. grepsrc <pattern> 搜索我的模式
  2. (尚未找到解决方案)
  3. sedsrc -i 's/<pattern>/replace/g'

不幸的是,这个解决方案不能让我满意。第一个问题是 sed 触摸所有文件,即使没有更改。然后,对我来说,使用别名的需要看起来不是很干净。

理想情况下,我希望有一个类似的工作流程:

注册一个新的上下文:

$ fetch register 'mysrcs' --recurse *.h *.c *.asm *.inc 

上下文列表:

$ fetch context
 1. mysrcs --recurse *.h *.c *.asm *.inc
 Extracted from ~/.fetchrc

找东西:

$ fetch files mysrcs /0x[a-f0-9]{3}/
./foo.c:235     Yeah 0x245
./bar.h:2       Oh yeah 0x2ac hex

测试替换:

$ fetch test mysrcs /0x[a-f0-9]{3}/0xabc/
./foo.c:235     Yeah 0xabc
./bar.h:2       Oh yeah 0xabc hex 

应用替换:

$ fetch subst --backup mysrcs /0x[a-f0-9]{3}/0xabc/
./foo.c:235     Yeah 0xabc
./bar.h:2       Oh yeah 0xabc hex 

Backup number: 242

出错时恢复:

$ fetch restore 242

这种工具对我来说看起来很标准。每个人都需要搜索和替换。我可以使用 Linux 中的标准替代方案吗?

【问题讨论】:

    标签: regex search replace sed grep


    【解决方案1】:
    #!/bin/ksh
    
    # Call the batch with the 2 (search than replace) pattern value as argument
    
    # assuming  the 2 pattern are "sed" compliant regex
    SearchStr="$1"
    ReplaceStr="$2"
    
    # Assuming it start the search from current folder and take any file
    # if more filter needed, use a find before with a pipe
    grep -l -r "$SearchStr" . | while read ThisFile
     do
        sed -i -e "s/${SearchStr}/${ReplaceStr}/g" ${ThisFile}
     done
    

    应该是适应您需要的基本脚本

    【讨论】:

    • 编写一个脚本来进行搜索/替换是我最初的想法之一。其实我是用perl做的。但我也有感觉,40 多年后的 unix/linux 工具应该有强大的工具,而不是一直要求改编基本脚本。你不这么认为吗?
    • 只使用一个脚本,允许对几个特定案例进行评论和轻松修改,但经过长期经验,像你一样,unix 工具非常好用,尤其是从 GUI 开始的新手还不是这样和向导。在这种情况下,脚本会稍微保护他们的操作(在直接命令行中使用 rm -fr 仍然有点害怕,其中缺少空格或额外的空格可能会产生非常可悲的效果:-D)
    【解决方案2】:

    我经常不得不执行这样的维护任务。我混合使用了findgrepsedawk

    我使用函数而不是别名。

    例如:

    # i. and ii.
    function grepsrc {
        find . -name "*.[ch]" -or -name "*.asm" -or -name "*.inc" -exec grep -Hn "$1"
    }
    
    # iii.
    function sedsrc {
        grepsrc "$1" | awk -F: '{print $1}' | uniq | while read f; do
            sed -i s/"$1"/"$2"/g $f
        done
    }
    

    使用示例:

    sedsrc "foo[bB]ar*" "polop"
    

    【讨论】:

      【解决方案3】:
      for F in $(grep -Rl <pattern>) ; do sed 's/search/replace/' "$F" | sponge "$F" ; done
      
      • grep-l 参数仅列出匹配的文件
      • 然后我们使用迭代器来运行那些通过 sed 匹配的文件
      • 我们使用moreutils 包中的sponge 程序将处理后的流写回同一文件

      这很简单,不需要额外的 shell 函数或复杂的脚本。

      如果您也想让它安全...将该文件夹签入 Git 存储库。这就是版本控制的用途。

      【讨论】:

        【解决方案4】:

        是的,有一个工具正是您正在寻找的。这是Git。当专业工具可以为您完成这项工作时,您为什么要管理文件备份以防出错?

        您将请求拆分为 3 个子问题:

        • 搜索到我的文件子集的速度有多快?
        • 如何临时应用替换,然后恢复到原始状态?
        • 如何替换到您的文件子集?

        我们首先需要在您的工作区做一些工作。您需要初始化一个 Git 存储库,然后将所有文件添加到该存储库中:

        $ cd my_project
        $ git init
        $ git add **/*.h **/*.c **/*.inc 
        $ git commit -m "My initial state"
        

        现在,您可以通过以下方式快速获取文件列表:

        $ git ls-files
        

        要进行替换,您可以使用sedperlawk。这里使用sed的例子:

        $ git ls-files | xargs sed -i -e 's/search/replace/'
        

        如果您对此更改不满意,您可以随时回滚:

        $ git checkout HEAD
        

        这使您可以随时测试您的更改并退后一步。

        现在,我们还没有简化命令。所以我建议给你的 Git 配置文件添加一个别名,通常位于这里~/.gitconfig。添加这个:

        [alias]
        sed = ! git grep -z --full-name -l '.' | xargs -0 sed -i -e
        

        所以现在你可以输入:

        $ git sed s/a/b/
        

        太神奇了……

        【讨论】:

          猜你喜欢
          • 2012-12-25
          • 1970-01-01
          • 1970-01-01
          • 2010-11-05
          • 2011-07-08
          • 2011-12-01
          • 1970-01-01
          • 2012-03-31
          相关资源
          最近更新 更多