()

Qiita Articles

公開記事のミラー・バックアップ

計算環境・Linux

renameコマンドが使えないときにファイル名を一括置換するワンライナー

Qiita公開: · 元記事更新:
バックアップ取得:

筆者自身のQiita記事を転載しています。内容は取得時点の記録です。Qiitaの元記事 · 原文Markdownを保存

この記事の目次

本稿ではrenameコマンドが使えないLinux環境においてファイル名を一括置換するワンライナーの例を紹介する。

forループを利用する場合

forループの使用が許容される場合は

bash系
for file in *test1*; do mv -n "$file" "${file/test1/test2}"; done
csh系
foreach file (*test1*) ; mv -n "$file" `echo "$file" | sed 's/test1/test2/'` ; end

などとすればよい。拡張子が .txt のファイルのみリネームしたい場合は *test1* の部分を *test1*.txt と書けばよい。

このうち、bash系のワンライナーの方が処理は速い。bashのワンライナーは、ループの中で外部プロセスを生成することなく、組み込み機能だけで処理を行うためである。

forループを利用しない場合

何らかの理由でforループの使用が躊躇われる場合は以下のようにする。

ファイル名の "test1" の部分を "test2" に一括置換するコマンド①
ls * | xargs -n 1 | sed 'p;s/test1/test2/g' | xargs -n 2 mv

この一連のコマンドは以下のように機能している。

  1. ls * でカレントディレクトリ内の全ファイルとディレクトリをリストする。
  2. xargs -n 1 でそれらを1行ずつ sed に渡す。
  3. sed 'p;s/test1/test2/g' で各ファイルについて変更前後の名前をそれぞれ出力する。1回目(pの部分)はそのまま、2回目(sで置換している部分)は test1 を test2 に置き換えたもの。
  4. xargs -n 2 mv で2つの引数をまとめて mv コマンドに渡し、ファイル名を変更する。最初の引数は元のファイル名、2番目の引数は新しいファイル名となる。-n オプションは同名のファイルが既に存在する場合に上書きを禁止する。

例えば、ディレクトリに次のファイルがある場合を考える。

file_test1.txt
file_test2.txt
test1_document.txt

この場合、コマンドは次のように動作する。

① ls * で全ファイルリストを取得:

file_test1.txt
file_test2.txt
test1_document.txt

② xargs -n1 で1行ずつ処理:

file_test1.txt
file_test2.txt
test1_document.txt

③ sed 'p;s/test1/test2/g' で各行を2回出力:

file_test1.txt
file_test2.txt
file_test2.txt
file_test2.txt
test1_document.txt
test2_document.txt

④ xargs -n 2 mv で2つの引数を渡し、mv でファイル名を変更:

mv file_test1.txt file_test2.txt
mv test1_document.txt test2_document.txt

先程のコマンドにより、ワンラインでこれを一括実行できる。
拡張子が .txt のファイルのみリネームしたい場合は ls * の部分を ls *.txt と書けばよい。

findを利用するケース

以下のように find コマンドを利用することもできる。カレントディレクトリ配下の全ファイルについて rename の操作を一括で実行したい場合には便利である。

ファイル名の "test1" の部分を "test2" に一括置換するコマンド③
find . -type f -name '*test1*' | sed 'p;s/test1/test2/' | paste - - | xargs -n 2 mv -n

paste - - によって標準入力を2行ずつ結合して一行にまとめている。
なお -n が2回登場しているが、 xargs コマンドの -n オプションと mv コマンドの -n オプションは別物なので、この形式で正しい。

find . -type f -name '*test1*' は現在のディレクトリ以下で名前に test1 を含むファイルを検索する。そのため、カレントディレクトリ配下の該当するすべてのファイルに mv コマンドが適用されることに注意。

sh を呼び出しているのでやや回りくどいが、以下の方法でも同様の処理が実行される。

ファイル名の "test1" の部分を "test2" に一括置換するコマンド②
find . -type f -name '*test1*' | xargs -I {} sh -c 'mv -n "$1" "${1//test1/test2}"' _ {}

環境によっては mv や ls などに特殊なaliasが設定されている場合もあるため、事前に挙動を検証してから実行することが推奨される。