使用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.\2\3/'

 

    要批量完成多個文件的上述操作, 使用 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.\2\3/'

 

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)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM