web-dev-qa-db-ja.com

コマンドラインから複数のファイルの拡張子を再帰的に変更するにはどうすればよいですか?

.abc拡張子を持つ多くのファイルがあり、それらを.edefgに変更したい
コマンドラインからこれを行う方法

ルートフォルダーには多くのサブフォルダーがあるため、ソリューションは再帰的に機能します。

71
tommyk

ポータブルな方法(POSIX準拠のシステムで動作します):

find /the/path -depth -name "*.abc" -exec sh -c 'mv "$1" "${1%.abc}.edefg"' _ {} \;

Bash4では、globstarを使用して再帰的なグロブ(**)を取得できます。

shopt -s globstar
for file in /the/path/**/*.abc; do
  mv "$file" "${file%.abc}.edefg"
done

Ubuntuの(Perl)renameコマンドは、Perlの正規表現構文を使用してファイルの名前を変更できます。これは、globstarまたはfindと組み合わせることができます。

# Using globstar
shopt -s globstar
files=(/the/path/**/*.abc)  

# Best to process the files in chunks to avoid exceeding the maximum argument 
# length. 100 at a time is probably good enough. 
# See http://mywiki.wooledge.org/BashFAQ/095
for ((i = 0; i < ${#files[@]}; i += 100)); do
  rename 's/\.abc$/.edefg/' "${files[@]:i:100}"
done

# Using find:
find /the/path -depth -name "*.abc" -exec rename 's/\.abc$/.edefg/' {} +

http://mywiki.wooledge.org/BashFAQ/0 も参照してください

84
geirha

すべてのファイルが同じフォルダーにある場合、これは必要なタスクを実行します

rename 's/.abc$/.edefg/' *.abc

ファイルの名前を再帰的に変更するには、次を使用します。

find /path/to/root/folder -type f -name '*.abc' -print0 | xargs -0 rename 's/.abc$/.edefg/'
44
Chakra

再帰的な名前変更の問題の1つは、ファイルの検索に使用する方法が何であれ、ファイル名だけでなくrenameにパス全体を渡すことです。そのため、ネストされたフォルダーで複雑な名前の変更を行うのが難しくなります。

この問題を解決するには、find-execdirアクションを使用します。 -execdirの代わりに-execを使用する場合、指定されたコマンドは、一致したファイルを含むサブディレクトリから実行されます。したがって、パス全体をrenameに渡すのではなく、./filenameのみを渡します。これにより、正規表現を簡単に記述できます。

find /the/path -type f \
               -name '*.abc' \
               -execdir rename 's/\.\/(.+)\.abc$/version1_$1.abc/' '{}' \;

詳細に:

  • -type fは、ディレクトリではなくファイルのみを検索することを意味します
  • -name '*.abc'は、.abcで終わるファイル名のみに一致することを意味します
  • -typeおよび-nameの後のバックスラッシュは、bashの行継続文字です。これらを使用してこの例を読みやすくしますが、実際には必要ありません。
  • ただし、-execdir行の最後にバックスラッシュが必要です。セミコロンをエスケープするためにあり、-execdirによって実行されたコマンドを終了します。楽しい!

正規表現の説明:

  • s/正規表現の開始
  • \.\/は、-execdirが渡す先頭の./と一致します。\を使用して、。および/メタキャラクター
  • (.+)はファイル名と一致します。括弧は、後で使用するために一致をキャプチャします
  • \.abcはドットをエスケープし、abcと一致します
  • $文字列の最後に一致を固定します

  • /は、正規表現の「一致」部分の終わりと「置換」部分の始まりを示します

  • version1_このテキストをすべてのファイル名に追加します

  • $1は、括弧でキャプチャしたため、既存のファイル名を参照します。 「一致」部分で括弧の複数のセットを使用する場合、$ 2、$ 3などを使用してここでそれらを参照できます。
  • .abc新しいファイル名は.abcで終わります。ここで「置換」セクションでドットメタキャラクターをエスケープする必要はありません。
  • /正規表現の終わり

tree --charset=ascii

|-- a_file.abc
|-- Another.abc
|-- Not_this.def
`-- dir1
    `-- nested_file.abc

tree --charset=ascii

|-- version1_a_file.abc
|-- version1_Another.abc
|-- Not_this.def
`-- dir1
    `-- version1_nested_file.abc

ヒント:renameの-​​nオプションは便利です。ドライランを実行し、変更する名前を表示しますが、変更は行いません。

13
Christian Long

別のポータブルな方法:

find /the/path -depth -type f -name "*.abc" -exec sh -c 'mv -- "$1" "$(dirname "$1")/$(basename "$1" .abc).edefg"' _ '{}' \;
5
aNeutrino
# Rename all *.txt to *.text
for f in *.txt; do 
mv -- "$f" "${f%.txt}.text"
done

lsを解析しない理由のエントリも参照してください。

編集:basenameを使用する必要がある場合、構文は次のようになります。

for f in *.txt; do
mv -- "$f" "$(basename "$f" .txt).text"
done

https://unix.stackexchange.com/questions/19654/changing-extension-to-multiple-files

3
ashanrupasinghe

これを実現する簡単な方法を見つけました。多くのファイルの拡張子をjpgからpdfに変更するには、次を使用します。

for file in /path/to; do mv $file $(basename -s jpg $file)pdf ; done
0
Peaceful

これが私がしたことであり、私が望んでいた通りに機能しました。 mvコマンドを使用しました。複数の.3gpファイルがあり、それらをすべて.mp4に名前変更したかった

以下に短いワンライナーを示します。

for i in *.3gp; do mv -- "$i" "ren-$i.mp4"; done

単に現在のディレクトリをスキャンし、すべての.3gpファイルを取得し、(mvを使用して)名前をren-name_of_file.mp4に変更します

0
Rexford

同じ名前のパッケージ から mmvコマンド を使用します。

mmv ';*.abc' '#1#2.edefg'

;は0個以上の*/と一致し、置換の#1に対応します。 *#2に対応します。非再帰バージョンは

mmv '*.abc' '#1.edefg'
0
MvG