シェルからファイルの一括置換の実行を素振りしてみる。その1

http://d.hatena.ne.jp/agt/20071101#p1のコメント欄で教えてもらったコマンドを今後のために「素振り」してみた。

まずid:dragon3さんのやつ。

dragon3『MavenReleasePlugin使えばいいじゃん、ていうのは置いておいて。
find . -name ’*.xml’ -print | xargs grep -l ”0.9.2-SNAPSHOT” | xargs perl -pi -e ’s/0¥.9¥.2-SNAPSHOT/0¥.9¥.2/g’
とかどうっすか?』

パイプでコマンドがつないであるので、ひとつづつ試してみる。まずは最初のコマンド。

find . -name '*.xml' -print

これは簡単。拡張子がxmlのファイルを探して、ファイル名をフルパスで標準出力へ出力。-printは結果を標準出力に出力するという意味だけど、なくてもとりあえず標準出力に出ているみたい。

実行結果はこんな感じ。

./cubby/pom.xml
./cubby/src/site/site.xml
./cubby-archetype/pom.xml
./cubby-archetype/src/main/resources/archetype-resources/pom.xml
./cubby-archetype/src/main/resources/archetype-resources/src/main/webapp/WEB-INF/web.xml
./cubby-archetype/src/main/resources/META-INF/maven/archetype.xml
./cubby-archetype/src/site/site.xml
./cubby-dist/build.xml
./cubby-dist/pom.xml
./cubby-dist/site/site.xml
./cubby-skin/pom.xml
./cubby-skin/src/site/site.xml
./cubby-tomcat55-support/pom.xml
./cubby-tomcat55-support/src/site/site.xml
./pom.xml
./src/site/site.xml

さて、次のコマンドはxargsとgrep

xargs grep -l "0.9.2-SNAPSHOT"

xargsは標準入力(findの結果)を改行か空白で区切って順番に次のコマンド(grep)に引数として渡して処理していくコマンド。grepは文字列の検索で、-lを指定するとファイル名のみ出力という意味。結果は以下。「-exec」でも同じことができるみたいだけどfind + xargs と find -exec の使い分け)を見るとあえて-execを使う場面はあまりなさそう。

-lなしの実行結果。

find . -name '*.xml' -print | xargs grep "0.9.2-SNAPSHOT"
./cubby/pom.xml:        <version>0.9.2-SNAPSHOT</version>
./cubby/src/site/site.xml:              <version>0.9.2-SNAPSHOT</version>
./cubby-archetype/pom.xml:      <version>0.9.2-SNAPSHOT</version>
./cubby-archetype/src/main/resources/archetype-resources/pom.xml:      <version>0.9.1</version>
./cubby-archetype/src/site/site.xml:            <version>0.9.2-SNAPSHOT</version>
./cubby-dist/pom.xml:    <version>0.9.2-SNAPSHOT</version>
./cubby-dist/site/site.xml:             <version>0.9.2-SNAPSHOT</version>
./cubby-skin/pom.xml:   <version>0.9.2-SNAPSHOT</version>
./cubby-skin/src/site/site.xml:         <version>0.9.2-SNAPSHOT</version>
./cubby-tomcat55-support/pom.xml:       <version>0.9.2-SNAPSHOT</version>
./cubby-tomcat55-support/src/site/site.xml:             <version>0.9.2-SNAPSHOT</version>
./pom.xml:  <version>0.9.2-SNAPSHOT</version>
./src/site/site.xml:            <version>0.9.2-SNAPSHOT</version>

-lありの実行結果。

find . -name '*.xml' -print | xargs grep -l "0.9.2-SNAPSHOT"
./cubby/pom.xml
./cubby/src/site/site.xml
./cubby-archetype/pom.xml
./cubby-archetype/src/main/resources/archetype-resources/pom.xml
./cubby-archetype/src/site/site.xml
./cubby-dist/pom.xml
./cubby-dist/site/site.xml
./cubby-skin/pom.xml
./cubby-skin/src/site/site.xml
./cubby-tomcat55-support/pom.xml
./cubby-tomcat55-support/src/site/site.xml
./pom.xml
./src/site/site.xml

対象のファイル一覧ができたところで、最後のコマンドはperl。

xargs perl -pi -e 's/0\.9\.2-SNAPSHOT/0\.9\.2/g'

xargsはさっきと同じ意味で、find+grepの結果のファイル名をperlコマンドに引数として渡すという意味。オプションには以下の意味があるみたい。-p便利。

  • -p ファイル名が引数として与えられた場合にファイルから読み込み、全行を処理する。
  • -i Webで調べたら「ファイルの内容を置換する」って書いてあるけど、おそらく「引数で指定されたファイルを、標準出力の結果と置換する」という意味だと思う。
  • -e 指定された文字列をプログラムとして実行する。

例えば、カレントディレクトにあるpom.xmlファイルを置換したいときは以下でできました。

perl -pi -e 's/0\.9\.2-SNAPSHOT/0\.9\.2/g' ./pom.xml

以上、勉強になりました。

RR 『t=/tmp/agt-$$ v=0.9.2; for i in `find . -name ¥*.xml -exec grep -q $v-SNAPSHOT {} ¥; -print` ; do cat $i | sed -e ”s/$v-SNAPSHOT/$v/” > $t; mv -i $t $i ; done;』

RRさんのやつも今度「素振り」してみます。