ファイル名・ディレクトリ名の一括置換
ここでは、ファイル名やディレクトリ名の一括置換のテクニックを紹介します。なお、UNIX系OSでは、「/
」(スラッシュ)と「\0
」(ヌル文字)の文字はファイル名やディレクトリ名として使用できません。
注意書きのないコマンド例に関しては、「\n
」(改行)や「\
」(バックスラッシュ)、「"
」(ダブルクォーテーション)などが含まれているファイル名・ディレクトリ名も置換できることを確認しています。
Windows NT系(2000, XP, Vista)のOSでは、Unicodeを内部コードとして利用しているため、ラテン文字などもファイル名・ディレクトリ名に使用できます。
ただし、Cygwin ではCP932(≒SJIS)で扱えない文字列がファイル名・ディレクトリ名に含まれると正しく処理できません。
同一階層内のすべてのファイル・ディレクトリ名に拡張子を付ける
下記のように拡張子を持たないファイルが複数存在しているとします。
$ ls test1 test2 test3 test4 test5
このファイルに、すべて「.bak」の拡張子をつけるには、シェルの制御構文を利用し、次のように指定できます。
$ for file in *; { mv "$file" "$file.bak"; }
xargs
コマンドを利用する場合は、次のように指定できます。
$ find * -maxdepth 0 -print0 | xargs -0 -I% mv % %.bak
find
コマンドのアクションを利用する場合は、次のように指定できます。
$ find * -maxdepth 0 -exec mv '{}' '{}.bak' \;
さらに、Debianではperlにより実装されたrename
コマンドが用意されています。第1引数にperl実行文が利用できるため、汎用的な指定ができます(改行文字が含まれるファイル名は置換されません)。
$ rename 's/$/.bak/' *
サブディレクトリに渡るすべてのファイル名から拡張子を取り除く
サブディレクトリに渡るファイル名から拡張子「.bak」を取り除くには、find
コマンドとシェルの制御構文を利用して、次のように指定できます。
$ find . -type f -name "*.bak" -print0 | while read -r -d '' file; do mv "$file" "${file%%.bak}"; done
上記の例では、シェルの変数展開「${パラメータ%%パターン}
」を用いて、ファイル名の後方から「.bak」にマッチした部分を除いています。シェルの変数展開に関しては、第0回を参考にしてください。
加えて、組み込みコマンドread
とシェルの変数展開を利用しています。
「-r
」オプションは、ファイル名に「\
」(バックスラッシュ)が含まれている場合を考慮して付けています。また「-d
」オプションで「\0
」(ヌル文字)を区切り文字に設定しています(「-d $'\0'
」と同様)。find
コマンドのオプションに関しては第1回を参照してください。
xargs
コマンドを利用する場合は、次のように指定できます。
$ find . -type f -name "*.bak" -print0 | perl -pe 's/\.bak\0/\0/g' | xargs -0 -I% mv %.bak %
perlを利用して「.bak\0
」文字を「\0
」(ヌル文字)に置換しています。また、「-p
」オプションは繰り返し処理と出力を行い、「-e
」オプションで与えられた文字列を実行します。
「perl -pe
」の代わりに「sed -e
」を利用すると、次のように指定できます(FreeBSDのsed
コマンドには対応していません)。
$ find . -type f -name "*.bak" -print0 | sed -e 's/\.bak\x00/\x00/g' | xargs -0 -I% mv %.bak %
「\x00
」は「\0
」(ヌル文字)の16進数表記です、8進数表記の「\o000
」でも構いません。
sed
コマンド、perlの詳細な使い方に関しては、次回以降に説明します。