Bashシェルスクリプト(コマンドライン)でファイル名の一括置換を行う(ファイル名にスペースあり)

Bash,CentOS,Docker,Linux,Ubuntu

はじめに

昨年後半から仕事が忙しく、ブログ投稿を行っていました。
些細なネタでもいいので毎日続けることが大事だと反省しました。

というのも、投稿を怠っていた間もブログを見てくれた方、訪問数、いいねの数が伸び続け、
月間の訪問者数もついに 5万PV/月 となっていたためです

ありがとうございます。

今年一発目の投稿は多くの人がご存知の一発ネタですね。
Bashで特定のフォルダ配下にあるファイルの名前を一括置換する方法です。

検証環境

----------
$ uname -moi
x86_64 x86_64 GNU/Linux

$ head -n 2 /etc/os-release
NAME="CentOS Linux"
VERSION="7 (Core)"

$ bash -version | head -n 1
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)
----------

準備

適当なファイルとフォルダを作ります。

# 適当なディレクトリを作成
$ mkdir -p dir1/ dir2/dir2-1

# 適当なファイルを作成
$ touch dir1/file-001.txt
$ touch dir2/file-002.txt
$ touch dir2/dir2-1/file-003.txt
$ touch dir3/dir3-1/file-004.txt
$ touch "dir3/dir3-1/file- -005.txt"

"file- -005.txt"だけ、ファイル名にスペースを含んでいることに注意です。

フォルダ構成を確認してみます。

$ tree -f
.
|-- ./dir1
|   `-- ./dir1/file-001.txt
|-- ./dir2
|   |-- ./dir2/dir2-1
|   |   `-- ./dir2/dir2-1/file-003.txt
|   `-- ./dir2/file-002.txt
`-- ./dir3
    `-- ./dir3/dir3-1
        |-- ./dir3/dir3-1/file-\ -005.txt
        `-- ./dir3/dir3-1/file-004.txt

5 directories, 5 files

一括置換を行う

find コマンドで実行した結果をループで読み込み mv しましょう。

# カレントディレクトリ配下のファイルを一覧表示してみる
$ find . -type f
./dir1/file-001.txt
./dir2/dir2-1/file-003.txt
./dir2/file-002.txt
./dir3/dir3-1/file-004.txt
./dir3/dir3-1/file-005.txt

# カレントディレクトリ配下のファイル名を一括置換( 00 → N )
$ find . -type f -print0 | while IFS= read -r -d $'\0' f; do mv "${f}" "${f//00/N}"; done

詳しい解説は後述します!

結果

結果を確認すると、正しくファイル名が一括置換されていることがわかります。

# 結果を確認
$ tree -f
.
|-- ./dir1
|   `-- ./dir1/file-N1.txt
|-- ./dir2
|   |-- ./dir2/dir2-1
|   |   `-- ./dir2/dir2-1/file-N3.txt
|   `-- ./dir2/file-N2.txt
`-- ./dir3
    `-- ./dir3/dir3-1
        |-- ./dir3/dir3-1/file-\ -N5.txt
        `-- ./dir3/dir3-1/file-N4.txt

5 directories, 5 files

解説

find . -type f でカレントディレクトリ配下のファイルを、サブディレクトリも含めて一覧出力します。

ポイントは -print0 です。
ファイル名の区切り文字を改行やスペースではなく null文字 にして出力します。

パイプでつなぎ、 find . -type f -print0 の結果を読み込みます。

while IFS= read -r -d $'\0' f という命令が多少複雑です。

IFS=-r-d $'\0' というオプションや環境変数はそれぞれ以下のような意味を持っています。

  • IFS= : readコマンドで読み込む際にスペースを区切り文字としない
  • -r : readコマンドで読み込む際に改行を区切り文字としない
  • -d $'\0' : readコマンドで読み込む際に null文字 を区切り文字とする

このようにしないと、スペースを含むファイルが存在した場合におかしな名前にリネームされたり、エラーが発生してしまったりします。

ひとこと

こうやって小ネタながら少しずつ続けていくことが大事ですよね。
「独学大全」を読んで反省しました。

今年もよろしくおねがいします。