Go言語_ディレクトリ名を再帰して変更する

Go言語でディレクトリ名の一部を変更します。

ディレクトリ名を変更する場合は、再帰処理を用いてサブディレクトリから順番に名前を変更する必要があります。



package main

import (
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

/*!
 * @brief     ディレクトリ名を変更する
 * @param[in] target  変更対象のディレクトリ名
 * @param[in] src     変更前の文字列
 * @param[in] dst     変更後の文字列
 * @return    error   エラー情報
 */
func renameDir(target string, src string, dst string) error {
	// 変更する文字列が存在するか確認する
	dirname, basename := filepath.Split(target)
	if !strings.Contains(basename, src) {
		return nil
	}

	// 変更後のファイルパスを作成する
	res := strings.Replace(basename, src, dst, -1)
	res = filepath.Join(dirname, res)

	// 変更する
	if err := os.Rename(target, res); err != nil {
		return err
	}

	return nil
}

/*!
 * @brief     ディレクトリ名を再帰的に変更する
 * @param[in] rootDir   変更対象のトップディレクトリ名
 * @param[in] src       変更前の文字列
 * @param[in] dst       変更後の文字列
 * @return    error     エラー情報
 */
func renameDirRecur(rootDir string, src string, dst string) error {

	files, err := ioutil.ReadDir(rootDir)
	if err != nil {
		return err
	}

	for _, file := range files {
		// ディレクトリのみを対象にする
		if !file.IsDir() {
			continue
		}

		// 子要素から名前を変更していく。
		subDir := filepath.Join(rootDir, file.Name())
		err = renameDirRecur(subDir, src, dst)
		if err != nil {
			return err
		}

		err = renameDir(subDir, src, dst)
		if err != nil {
			return err
		}
	}
	return nil
}

/*!
 * @brief  初期化処理
 * @retval string ディレクトリ名
 * @retval string 変換文字列
 * @retval error  エラー情報
 */
func initialize() ([]string, bool, error) {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [OPTION]... SOURCE DEST:\n",
			filepath.Base(os.Args[0]))
		flag.PrintDefaults()
	}

	optR := flag.Bool("r", false, "recursive mode")
	flag.Parse()

	if flag.NArg() != 3 {
		flag.Usage()
		return nil, false, errors.New("Error: Invalid arguments.")
	}

	return flag.Args(), *optR, nil
}

/*!
 * @brief   main routine
 * @return  成功時には0を返し、失敗時には1を返す。
 */
func main() {
	targets, recurMode, err := initialize()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	if recurMode {
		err = renameDirRecur(targets[0], targets[1], targets[2])
	} else {
		err = renameDir(targets[0], targets[1], targets[2])
	}
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	os.Exit(0)
}

コマンド実行例

「dir1」ディレクトリ配下に存在する「abc」ディレクトリを「acb」という名前に変更する場合、下記のように実行します。


go run renamer.go dir1 bc cb

「-r」を付加するとサブディレクトリを含んでディレクトリ名を変更します。


go run renamer.go -r dir2 bc cb

例えば、npmインストールにより生成されたnode_modulesから、ハイフンやドットのような不要文字を削除したい場合、下記のように実行します。


go run renamer.go -r node_modules - ""
go run renamer.go -r node_modules . ""


関連ページ