6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

特定のディレクトリ配下の特定文字列を一括して置換する便利スクリプト

Last updated at Posted at 2015-08-26

はじめに

なぜ急にこんな事をしたくなったのか。
とあるファイルのファイル名を修正しました。
ところが、調べてみるとそのファイルを参照しているコードがたくさんあることに気づき、すべて置換しないといけなくなった。
という背景がありました。

例題

次のように、ファイルをリネームしました。

CreateIten.php -> CreateItem.php

すると、itemディレクトリ配下でCreateIten.phpを使っているコードがたくさん見つかりました。
このコードを一括で置換したいです。

とりあえず調査してみる

[riki@hoge]$ find ./ -type f | xargs grep CreateIten.php
./item/Item_13.php:require_once __DIR__.'/../CreateIten.php';
./item/Item_4.php:require_once __DIR__.'/../CreateIten.php';
./item/Item_9.php:require_once __DIR__.'/../CreateIten.php';
./item/Item_19.php:require_once __DIR__.'/../CreateIten.php';
./item/Item_20.php:require_once __DIR__.'/../CreateIten.php';
./item/Item_18.php:require_once __DIR__.'/../CreateIten.php';
./item/Item_14.php:require_once __DIR__.'/../CreateIten.php';
./item/Item_6.php:require_once __DIR__.'/../CreateIten.php';
./item/Item_12.php:require_once __DIR__.'/../CreateIten.php';
./item/Item_11.php:require_once __DIR__.'/../CreateIten.php';
./item/Item_10.php:require_once __DIR__.'/../CreateIten.php';
./item/Item_17.php:require_once __DIR__.'/../CreateIten.php';
./item/Item_7.php:require_once __DIR__.'/../CreateIten.php';
./item/Item_1.php:require_once __DIR__.'/../CreateIten.php';
./item/Item_2.php:require_once __DIR__.'/../CreateIten.php';
./item/Item_16.php:require_once __DIR__.'/../CreateIten.php';
./item/Item_3.php:require_once __DIR__.'/../CreateIten.php';
./item/Item_8.php:require_once __DIR__.'/../CreateIten.php';
./item/Item_15.php:require_once __DIR__.'/../CreateIten.php';
./item/Item.php:require_once __DIR__.'/../CreateIten.php';
./item/Item_5.php:require_once __DIR__.'/../CreateIten.php';

なるほど、どうやらitemディレクトリ配下で使われているみたいだ。

  • 因みに・・@heliac2000さんからコメントで頂いたテクニックとして、grepの-lオプションを使ってファイル名だけを出力することも可能だそうです

find ./ -type f | xargs grep CreateIten.php

(このようにすれば、こここから↓のawkとかを使った処理は不要となります)

とりあえず、対象のファイルを洗い出したい

↑のコマンドだと、同じコード内に2箇所以上ある場合、同じファイルが2つ出てくる。
対象ファイルをユニークで洗い出したいので、下記のステップを踏めば出せそうだ。

  • まずはgrepの結果からファイル名を出力
    • ↑の結果を、:区切りにして、1列目を出力したい
  • 重複を排除する
    • sortして、uniqかければOKそう

実践!

[riki@hoge]$ find ./ -type f | xargs grep CreateIten.php | awk -F: '{print $1}' | sort | uniq
./item/Item.php
./item/Item_1.php
./item/Item_10.php
./item/Item_11.php
./item/Item_12.php
./item/Item_13.php
./item/Item_14.php
./item/Item_15.php
./item/Item_16.php
./item/Item_17.php
./item/Item_18.php
./item/Item_19.php
./item/Item_2.php
./item/Item_20.php
./item/Item_3.php
./item/Item_4.php
./item/Item_5.php
./item/Item_6.php
./item/Item_7.php
./item/Item_8.php
./item/Item_9.php

うん。よさ気。
パイプで渡してるものを一応解説しておきます。

コマンド 意味
awk -F: 受け取った結果の区切り文字を:にする
`{print $1}' :で区切った結果の1列目を出力
sort ファイルでソートをかける
uniq ユニークを取る

じゃあ、一旦ここでスクリプトファイルを作っておく

replace.shという名前のスクリプトを作って、実行権限を与えておきます。

[riki@hoge]$ touch replace.sh
[riki@hoge]$ chmod +x replace.sh 

一旦、さっきコマンドをスクリプトに書いて、ちゃんとファイルが出力されるか見てみよう。

replace.sh
# /bin/sh

find ./ -type f | xargs grep CreateIten.php | awk -F: '{print $1}' | sort | uniq
[riki@hoge]$ ./replace.sh 
./item/Item.php
./item/Item_1.php
./item/Item_10.php
./item/Item_11.php
./item/Item_12.php
./item/Item_13.php
./item/Item_14.php
./item/Item_15.php
./item/Item_16.php
./item/Item_17.php
./item/Item_18.php
./item/Item_19.php
./item/Item_2.php
./item/Item_20.php
./item/Item_3.php
./item/Item_4.php
./item/Item_5.php
./item/Item_6.php
./item/Item_7.php
./item/Item_8.php
./item/Item_9.php
./replace.sh

あぁ。自分自身のファイルが出てきてしまった。
そうですよね。スクリプトの中にgrep書いてるので、それが引っかかっているのです。
じゃあ、無視するようにしておきましょう。

replace.sh
# /bin/sh

find ./ -type f | xargs grep CreateIten.php | grep -v replace.sh | awk -F: '{print $1}' | sort | uniq

3個目のパイプでgrep -v replace.shと書いて、自分自身を無視するようにしました。

[riki@hoge]$ ./replace.sh 
./item/Item.php
./item/Item_1.php
./item/Item_10.php
./item/Item_11.php
./item/Item_12.php
./item/Item_13.php
./item/Item_14.php
./item/Item_15.php
./item/Item_16.php
./item/Item_17.php
./item/Item_18.php
./item/Item_19.php
./item/Item_2.php
./item/Item_20.php
./item/Item_3.php
./item/Item_4.php
./item/Item_5.php
./item/Item_6.php
./item/Item_7.php
./item/Item_8.php
./item/Item_9.php

よーしいい感じ。

じゃあ、これらのファイルに置換をかけていく

更に、少し汎用性を持たせる為に、置換前文字列を第一引数に、
置換後の文字列を第2引数に渡せるような仕様にしてみました。

replace.sh
# /bin/sh

COMMAND=`basename $0`

if [ $# -ne 2 ] ; then
    echo "usage ${COMMAND} [before] [after]"
    exit;
fi

BEFORE=$1
AFTER=$2

for file in `find ./ -type f | xargs grep CreateIten.php | grep -v replace.sh | awk -F: '{print $1}' | sort | uniq`
do
  echo "replacing $file before:$BEFORE afiter:$AFTER"
  cp $file $file"_tmp"
  sed -e "s/${BEFORE}/${AFTER}/" $file"_tmp" > $file
  rm $file"_tmp"
done

実践!

[riki@hoge]$ ./replace.sh CreateIten.php CreateItem.php
replacing ./item/Item.php before:CreateIten.php afiter:CreateItem.php
replacing ./item/Item_1.php before:CreateIten.php afiter:CreateItem.php
replacing ./item/Item_10.php before:CreateIten.php afiter:CreateItem.php
replacing ./item/Item_11.php before:CreateIten.php afiter:CreateItem.php
replacing ./item/Item_12.php before:CreateIten.php afiter:CreateItem.php
replacing ./item/Item_13.php before:CreateIten.php afiter:CreateItem.php
replacing ./item/Item_14.php before:CreateIten.php afiter:CreateItem.php
replacing ./item/Item_15.php before:CreateIten.php afiter:CreateItem.php
replacing ./item/Item_16.php before:CreateIten.php afiter:CreateItem.php
replacing ./item/Item_17.php before:CreateIten.php afiter:CreateItem.php
replacing ./item/Item_18.php before:CreateIten.php afiter:CreateItem.php
replacing ./item/Item_19.php before:CreateIten.php afiter:CreateItem.php
replacing ./item/Item_2.php before:CreateIten.php afiter:CreateItem.php
replacing ./item/Item_20.php before:CreateIten.php afiter:CreateItem.php
replacing ./item/Item_3.php before:CreateIten.php afiter:CreateItem.php
replacing ./item/Item_4.php before:CreateIten.php afiter:CreateItem.php
replacing ./item/Item_5.php before:CreateIten.php afiter:CreateItem.php
replacing ./item/Item_6.php before:CreateIten.php afiter:CreateItem.php
replacing ./item/Item_7.php before:CreateIten.php afiter:CreateItem.php
replacing ./item/Item_8.php before:CreateIten.php afiter:CreateItem.php
replacing ./item/Item_9.php before:CreateIten.php afiter:CreateItem.php

うまくいってそう!
よし、じゃあ実際に置換できているのか確かめてみましょう。

# 置換前の文字列はもうなくなってる
[riki@hoge]$ find ./ -type f | xargs grep CreateIten.php | grep -v replace.sh 

# 置換後のやつになってるかなー
[riki@hoge]$ find ./ -type f | xargs grep CreateItem.php | grep -v replace.sh 
./item/Item_13.php:require_once __DIR__.'/../CreateItem.php';
./item/Item_4.php:require_once __DIR__.'/../CreateItem.php';
./item/Item_9.php:require_once __DIR__.'/../CreateItem.php';
./item/Item_19.php:require_once __DIR__.'/../CreateItem.php';
./item/Item_20.php:require_once __DIR__.'/../CreateItem.php';
./item/Item_18.php:require_once __DIR__.'/../CreateItem.php';
./item/Item_14.php:require_once __DIR__.'/../CreateItem.php';
./item/Item_6.php:require_once __DIR__.'/../CreateItem.php';
./item/Item_12.php:require_once __DIR__.'/../CreateItem.php';
./item/Item_11.php:require_once __DIR__.'/../CreateItem.php';
./item/Item_10.php:require_once __DIR__.'/../CreateItem.php';
./item/Item_17.php:require_once __DIR__.'/../CreateItem.php';
./item/Item_7.php:require_once __DIR__.'/../CreateItem.php';
./item/Item_1.php:require_once __DIR__.'/../CreateItem.php';
./item/Item_2.php:require_once __DIR__.'/../CreateItem.php';
./item/Item_16.php:require_once __DIR__.'/../CreateItem.php';
./item/Item_3.php:require_once __DIR__.'/../CreateItem.php';
./item/Item_8.php:require_once __DIR__.'/../CreateItem.php';
./item/Item_15.php:require_once __DIR__.'/../CreateItem.php';
./item/Item.php:require_once __DIR__.'/../CreateItem.php';
./item/Item.php:CreateItem.php
./item/Item_5.php:require_once __DIR__.'/../CreateItem.php';

出来たー!
使い勝手あまりよくなさそうですが、一応gitに上げておきます。

6
5
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?