• 使用Sed和Awk实现批量文件的文本替换


         摘要: 使用 Sed 完成文本替换操作任务是非常合适的。结合 find 命令,即可实现指定批量文件的文本替换。同时给出了Awk的解决方案作为对比。

    问题

         现在, 我要将一个原有Java项目中的一些包及下面的类移到另一个Java项目中复用(一个实际场景是,将自己工具箱的常用框架、工具包及类挪到具体项目中使用)。

         Project javastudy:

         Packages:

              algorithm/ ,  foundations/,  javatech/, patterns/, threadprogramming/, datastructure/, javagui/, junitest3/, testdata/,  utils/

           这些包下面会有很多子包。

           现在要把这些包及其子包下面的所有 Java 文件移动到 Project ALLIN, 放在 package:  zzz.study 下面。

    思路

          在尝试使用 Eclipse 包重构无效之后, 我还是采用了最直观的方案: 将 Project javastudy 的上述包直接复制到 Project ALLIN 的包 zzz.study 下面。 复制之后, 要解决一个问题是: 必须手动更改每个 Java 文件的 package , import 引用。 比如 algorithm/BitsMapSort.java 中 

    package algorithm.sort;
    
    import java.util.Arrays;
    import datastructure.vector.NBitsVector;  

         必须改成:

    package zzz.study.algorithm.sort;
    
    import java.util.Arrays;
    import zzz.study.datastructure.vector.NBitsVector;

         也就是说, 要将指定包的多个Java文件里的 package packageName 和 import packageName 批量替换成 package zzz.study.packageName ,  import zzz.study.packageName, 其中 packageName 取以下这些值: algorithm ,  foundations,  javatech, patterns, threadprogramming, datastructure, javagui, junitest3, testdata,  utils 。

    Sed解决方案 

         难道真的要手动修改这么多文件的包和导入引用么? 

         于是想到了使用Sed. 注意到, 关键是匹配到 package|import packageName 即可。 可以使用分组和引用来完成。 命令如下: 

    sed -r -i 's/(package|import) (algorithm|foundations|javatech|patterns|threadprogramming|datastructure|javagui|junitest3|testdata|utils)(.*)/1 zzz.study.23/'

        要批量完成多个文件的上述操作, 使用 find | xargs 即可:  

    find . -name "*.java" | xargs sed -r -i 's/(package|import) (algorithm|foundations|javatech|patterns|threadprogramming|datastructure|javagui|junitest3|testdata|utils)(.*)/1 zzz.study.23/'

    Awk解决方案

        显然,有了 find 命令,只要处理好单个文件的文本替换,然后使用 for 循环依次处理即可。 awk 处理单个文件的文本替换如下代码所示。 ARGV[1] 是传入的文件名,通常生成一个临时文件然后去覆写原来的文件,获得就地修改的效果。system 用来调用 shell 命令,挺好的特性。 ~ 用于匹配行是否满足某种条件。awk -f replace.awk BitsMapSort.java 用指定的 awk 程序 replace.awk 来处理指定文件 BitsMapSort.java。

         $ cat replace.awk

         $ awk -f replace.awk BitsMapSort.java

    BEGIN {
            origin_filename = ARGV[1]
            print origin_filename
            filename = origin_filename".tmp"
    }
    {
            if ($0 ~ /^(package|import) (algorithm|foundations|javatech|patterns|threadprogramming|datastructure|javagui|junitest3|testdata|utils).*/) {
                    print $1" zzz.study."$2 >> filename
            }
            else {
                    print $0 >> filename
            }
    
    }
    END {
           cmd = "mv "filename" "origin_filename
           system(cmd)
    }

         批量处理文件替换的命令是:

    for file in $(find . -name '*.txt'); do awk -f replace.awk $file;  done

    小结

          本文分别使用Sed和Awk两个小工具来实现批量文件的文本替换。可以看到 Sed 由于具备就地修改的特性,比 Awk 实现要简洁的多。为什么还要使用Awk来实现呢? 一个重要原因是期望拥有多种解决途径和视角,不局限于单一方案。Awk 在规则的记录文件处理可以显示出更强大的威力,而Sed在任意文本内容替换上更具优势。   

           Sed 用法参考文章:

              1.  Linux 之 Sed 用法

              2.  Sed替换

              3.  Sed命令的工作原理

              4.  Sed&Awk 读书笔记之Sed

              5.  sed高级用法:模式空间(pattern space)和保持空间(hold space)

  • 相关阅读:
    misc子系统
    Spring boot+RabbitMQ环境
    Linux input
    lnmp环境的搭建
    DDD的.NET开发框架
    【踩坑记】从HybridApp到ReactNative
    Migrating from IntelliJ Projects
    Windows下Redis中RedisQFork位置调整
    远程仓库版本回退方法 good
    maven repository
  • 原文地址:https://www.cnblogs.com/lovesqcc/p/4379007.html
Copyright © 2020-2023  润新知