Ganti nama file secara berulang (ubah ekstensi) di Linux

22

Bagaimana cara mengganti nama semua file dalam direktori, secara rekursif, mengubah satu ekstensi file ke yang lain, untuk ribuan file dalam ribuan subfolder? Saya melihat banyak perintah yang melakukan hampir apa yang saya inginkan, tetapi tidak cukup.

find . -name "*.andnav" -exec rename .andnav .tile {} \;
syntax error at (eval 1) line 1, near "."

...

rename -nv 's/\.andnav$/\.tile/i' *.andnav
0.png.andnav renamed as 0.png.tile
endolith
sumber
1
Apakah Anda punya Debian renameatau Red Hat rename?
Ignacio Vazquez-Abrams
@Ignacio: Ubuntu = Debian?
endolith
Ya, Ubuntu adalah turunan Debian.
Ignacio Vazquez-Abrams

Jawaban:

23

Menemukannya

find . -name "*.andnav" -exec rename -v 's/\.andnav$/\.tile/i' {} \;
./0/0.png.andnav renamed as ./0/0.png.tile
./0/1.png.andnav renamed as ./0/1.png.tile
./1/0.png.andnav renamed as ./1/0.png.tile
./1/1.png.andnav renamed as ./1/1.png.tile

tentu saja menghapus -v ketika benar-benar melakukannya, atau itu akan membuang waktu untuk menampilkan semua file

endolith
sumber
14

Sesuatu seperti:

find . -name '*.andnav' -exec sh -c 'mv "$0" "${0%.andnav}.tile"' {} \;
cYrus
sumber
ini bekerja paling baik untuk saya
cwd
14

Dengan zsh:

autoload zmv
zmv -n '(**/)(*).andnav' '$1$2.tile'

Hapus -nuntuk benar-benar melakukan penggantian nama.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
1
Jawaban yang fantastis!
Chris Knadler
4

Saya menemukan metode ini lebih mudah dan lebih mudah dibaca:

find . -name "*.andnav" | rename "s/\.andnav$/.tile/"

Setidaknya pada derivasi Ubuntu rename mengambil daftar file dari STDIN jika tidak ada yang ada di baris perintah. Dan ini dapat diuji dengan mudah dengan:

find . -name "*.andnav" | rename -vn "s/\.andnav$/.tile/"

sampai Anda melakukannya dengan benar.

Bernd Wechner
sumber
1

Ganti nama file dan direktori dengan find -execdir | rename

Jika Anda akan mengubah nama file dan direktori tidak hanya dengan akhiran, maka ini adalah pola yang baik:

PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
  find . -depth -execdir rename 's/findme/replaceme/' '{}' \;

-execdirOpsi yang luar biasa melakukan a cdke direktori sebelum mengeksekusi renameperintah, tidak seperti -exec.

-depth memastikan bahwa penggantian nama terjadi pertama kali pada anak-anak, dan kemudian pada orang tua, untuk mencegah kemungkinan masalah dengan direktori orang tua yang hilang.

-execdir diperlukan karena penggantian nama tidak berfungsi dengan baik dengan jalur input non-basename, misalnya yang gagal:

rename 's/findme/replaceme/g' acc/acc

The PATHhacking diperlukan karena -execdirmemiliki satu kelemahan yang sangat mengganggu: findyang sangat dogmatis dan menolak untuk melakukan apa saja dengan -execdirjika Anda memiliki path relatif di Anda PATHvariabel lingkungan, misalnya ./node_modules/.bin, gagal dengan:

find: Path relatif './node_modules/.bin' termasuk dalam variabel lingkungan PATH, yang tidak aman dalam kombinasi dengan aksi -execdir dari find. Harap hapus entri itu dari $ PATH

Lihat juga: /ubuntu/621132/why-using-the-execdir-action-is-insecure-for-directory-which-is-in-in-the-path/1109378#1109378

-execdiradalah ekstensi menemukan GNU ke POSIX . renameberbasis Perl dan berasal dari renamepaket. Diuji di Ubuntu 18.10.

Ganti nama lookahead workaround

Jika jalur input Anda tidak berasal find, atau jika Anda sudah cukup mengalami gangguan jalur relatif, kita dapat menggunakan beberapa Perl lookahead untuk mengganti nama direktori dengan aman seperti di:

git ls-files | sort -r | xargs rename 's/findme(?!.*\/)\/?$/replaceme/g' '{}'

Saya belum menemukan analog yang cocok untuk -execdirdengan xargs: Xargs: ubah direktori kerja ke path file sebelum dieksekusi?

The sort -rdiperlukan untuk memastikan bahwa file datang setelah direktori masing-masing, karena jalur lagi datang setelah yang lebih pendek dengan awalan yang sama.

Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
sumber