Jawaban:
Cara portabel (yang akan bekerja pada sistem yang mendukung POSIX):
find /the/path -depth -name "*.abc" -exec sh -c 'mv "$1" "${1%.abc}.edefg"' _ {} \;
Di bash4, Anda dapat menggunakan globstar untuk mendapatkan gumpalan rekursif (**):
shopt -s globstar
for file in /the/path/**/*.abc; do
mv "$file" "${file%.abc}.edefg"
done
Perintah (perl) renamedi Ubuntu dapat mengganti nama file menggunakan sintaks ekspresi reguler perl, yang dapat Anda gabungkan dengan globstar atau 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/' {} +
Juga lihat http://mywiki.wooledge.org/BashFAQ/030
${1%.abc}...
sh -c argumen pertama ditugaskan ke $ 0 dan argumen yang tersisa ditugaskan ke parameter posisi . Jadi _argumen dummy, dan '{}' adalah argumen posisi pertama sh -c.
Ini akan melakukan tugas yang diperlukan jika semua file ada di folder yang sama
rename 's/.abc$/.edefg/' *.abc
Untuk mengganti nama file secara rekursif, gunakan ini:
find /path/to/root/folder -type f -name '*.abc' -print0 | xargs -0 rename 's/.abc$/.edefg/'
rename 's/.abc$/.edefg/' /path/to/root/folder/**/*.abcdalam versi modern Bash.
sdi awal, dan opsi apa yang bisa saya gunakan di sana. Terima kasih!
Satu masalah dengan pengubahan nama rekursif adalah bahwa metode apa pun yang Anda gunakan untuk mencari file, ia meneruskan seluruh path rename, bukan hanya nama file. Itu membuatnya sulit untuk melakukan penggantian nama yang kompleks di folder bersarang.
Saya menggunakan find's -execdirtindakan untuk memecahkan masalah ini. Jika Anda menggunakan -execdiralih-alih -exec, perintah yang ditentukan dijalankan dari subdirektori yang berisi file yang cocok. Jadi, alih-alih melewati seluruh jalan menuju rename, itu hanya melewati ./filename. Itu membuatnya lebih mudah untuk menulis regex.
find /the/path -type f \
-name '*.abc' \
-execdir rename 's/\.\/(.+)\.abc$/version1_$1.abc/' '{}' \;
Secara terperinci:
-type f berarti hanya mencari file, bukan direktori-name '*.abc' berarti hanya cocok dengan nama file yang berakhiran .abc'{}'adalah placeholder yang menandai tempat di mana -execdirakan memasukkan jalan yang ditemukan. Kutipan tunggal diperlukan, untuk memungkinkannya menangani nama file dengan spasi dan karakter shell.-typedan -nameadalah karakter lanjutan garis bash. Saya menggunakannya untuk membuat contoh ini lebih mudah dibaca, tetapi mereka tidak diperlukan jika Anda menempatkan perintah Anda semua pada satu baris.-execdirbaris diperlukan. Itu ada untuk melarikan diri dari titik koma, yang mengakhiri perintah dijalankan oleh -execdir. Menyenangkan!Penjelasan regex:
s/ mulai dari regex\.\/cocok dengan yang terdepan ./ yang -execdir lewati. Gunakan \ untuk menghindari. dan / metakarakter (catatan: bagian ini bervariasi tergantung pada versi Anda find. Lihat komentar dari pengguna @apollo)(.+)cocok dengan nama file. Tanda kurung menangkap pertandingan untuk digunakan nanti\.abc lepas titik, cocok dengan abc$ jangkar korek api di ujung senar
/ menandai akhir bagian "cocok" dari regex, dan awal bagian "ganti"
version1_ tambahkan teks ini ke setiap nama file
$1referensi nama file yang ada, karena kami menangkapnya dengan tanda kurung. Jika Anda menggunakan beberapa set tanda kurung di bagian "cocok", Anda dapat merujuknya di sini menggunakan $ 2, $ 3, dll..abcnama file baru akan berakhiran .abc. Tidak perlu keluar dari metacharacter titik di sini di bagian "ganti"/ akhir regexSebelum
tree --charset=ascii
|-- a_file.abc
|-- Another.abc
|-- Not_this.def
`-- dir1
`-- nested_file.abc
Setelah
tree --charset=ascii
|-- version1_a_file.abc
|-- version1_Another.abc
|-- Not_this.def
`-- dir1
`-- version1_nested_file.abc
Petunjuk: renameopsi -n berguna. Itu menjalankan kering dan menunjukkan kepada Anda apa nama itu akan berubah, tetapi tidak membuat perubahan.
--execdirtidak lulus dalam memimpin ./sehingga \.\/bagian dalam regex dapat dihilangkan. Mungkin itu karena saya menggunakan OSX bukan ubuntu
Cara portabel lainnya:
find /the/path -depth -type f -name "*.abc" -exec sh -c 'mv -- "$1" "$(dirname "$1")/$(basename "$1" .abc).edefg"' _ '{}' \;
# Rename all *.txt to *.text
for f in *.txt; do
mv -- "$f" "${f%.txt}.text"
done
Lihat juga entri tentang mengapa Anda tidak perlu menguraikan ls.
Sunting: jika Anda harus menggunakan nama samaran, sintaks Anda adalah:
for f in *.txt; do
mv -- "$f" "$(basename "$f" .txt).text"
done
https://unix.stackexchange.com/questions/19654/changing-extension-to-multiple-files
Inilah yang saya lakukan dan bekerja persis seperti yang saya inginkan. Saya menggunakan mvperintah. Saya memiliki banyak .3gpfile dan saya ingin mengubah nama semuanya.mp4
Berikut adalah daftar singkat untuk itu:
for i in *.3gp; do mv -- "$i" "ren-$i.mp4"; done
Yang cukup memindai melalui direktori saat ini, mengambil semua file .3gp, lalu mengganti nama (menggunakan mv) ke ren-name_of_file.mp4
file.3gpmenjadi file.3gp.mp4, yang mungkin bukan yang diinginkan kebanyakan orang.
.3gpatau .mp4di sini hanya untuk tujuan ilustrasi.
basename "$i" .mp4untuk menghapus ekstensi sebelumnya, bukan "ren- $ i.mp4".
Saya akan menggunakan perintah mmv dari paket dengan nama yang sama :
mmv ';*.abc' '#1#2.edefg'
The ;pertandingan nol atau lebih */dan sesuai dengan #1di penggantian. The *bersesuaian untuk #2. Versi non-rekursif akan menjadi
mmv '*.abc' '#1.edefg'
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 dalam 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 berikut:
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: Mengapa menggunakan tindakan '-execdir' tidak aman untuk direktori yang ada di PATH?
-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: https://superuser.com/questions/893890/xargs-change-working-directory-to-file-path-before-executing/915686
The sort -rdiperlukan untuk memastikan bahwa file datang setelah direktori masing-masing, karena jalur lagi datang setelah yang lebih pendek dengan awalan yang sama.