share facebook facebook2 twitter menu hatena pocket slack

2015.06.29 MON

find & xargs で ディレクトリ内一括置換、リカバリも考えて

WRITTEN BY今岡 久敏

私は考えていた。

「このままEmacsの道を歩むのか、それともatomとやらを使うべきか。。」 atom使ってみたけどいい感じ!Emacsキーバインドも使えるし、、と思ったけど、私だけにとって致命的な欠陥が、commandキーを altキーと扱ってくれない点です。もっと上からキーバインドをいじって、alt <=> command をやればいいけど、そうするとatom特有の操作が気持ち悪くなる。のでやめとこうとなった。 もともと、Emacsを使うようになったのは、実は仕方なしであって、本当はwindowsのxyzzyというソフトを使っていた。今回は、そのxyzzyにある、gresregという機能と同じことをやりたいというお話。ちなみにatomは余裕で出来そう。たぶん

gresregとは?

特定のディレクトリ配下のファイルにgrepかけてreplaceもするというものです。なんとEmacsに無い機能なんです。

そんなのコマンドで楽勝でしょ!

英語だけで生きている人ならば多分大丈夫でしょうが、問題は日本語です。文字コードが混ざり、且つ日本語を置換するとなると、ワンライナーはチョットなと思う。 xyzzyの例ですが、参考に。日本語が絡むとエディタの仕事ですね。 http://xyzzy.s53.xrea.com/wiki/index.php?QuickTour%2Fgresreg

emacsにおける gresregは?

Meadowで実装があるとのことで、パッケージでは入らないですが、あります。
http://www.bookshelf.jp/soft/meadow_49.html#SEC735
githubにある奴は、日本語が化けているので注意

だけど、xyzzyとの違いは大きく、ディレクトリを指定することが出来ず、あくまで対象は開いているバッファ全てとなります。まあ、作ればいいんですが。。

しゃあないからコマンドでやる。やれて損はないし

find & xargs ですね。これも今更知りましたが、 find & xargs をやるなら、 find -print0, xargs -0 は必須と言っていいでしょう。スペースを含むファイルパス名が上手く捌けないからです。

普通にgresreg

find . -type f -name "*.txt" -print0 | xargs -0 sed -i.bak -e s/age/sage/g

-i の後にprifixをつけたら、その名前でバックアップファイルを作ります。バックアップなしだと怖いので、.bakは必須かと
そもそも、対象ディレクトリがきっちりわかってて、まるごとバックアップ可能だったら、先にバックアップ取るほうがいいですね。

変更対象を洗い出す

diff の力を借りる。

find . -type f -name "*.txt" -print0 | xargs -0 -I{} diff -u {} {}.bak

xargs -I は、実行対象のコマンドで、xargsにわたってくる引数を2回使ったり、位置を変えたりするときに使う。{}がよく使われているのは、単にバッティングしにくい名前ってだけなので、なんでもいい
diffのオプションをもう少しいじれば、情報は色々コントロールできるはず、ファイル名だけとか。sedは、置換が起ころうが起こらまいがバックアップファイルを生成するので、これでいける。

リカバリ 元に戻すとき

find . -type f -name "*.txt" -print0 | xargs -0 -I{} mv {}.bak {}

バックアップはもう要らないから消すとき

find . -type f -name "*.bak" -delete

ここはfind単体でいける

まとめ

  • インフラエンジニアは正直コマンドで十分。だけど日本語ファイルを使う人は、gresregはエディタにやらすべき。
  • find -print0 & xargs -0 は正直デフォルトでよくね?
  • こんなコマンド、年に3回叩けばいい位、だからすぐ忘れる、だから忘れないように書いておく

元記事はこちら

find & xargs で ディレクトリ内一括置換、リカバリも考えて

今岡 久敏

「常に新しいモノの方が、古いモノより優れている、というマインドを持てなくなった時、それはエンジニアとしての死を意味する」え、誰の言葉だって?俺の言葉だよ。