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) rename
di 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/**/*.abc
dalam versi modern Bash.
s
di 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 -execdir
tindakan untuk memecahkan masalah ini. Jika Anda menggunakan -execdir
alih-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 -execdir
akan memasukkan jalan yang ditemukan. Kutipan tunggal diperlukan, untuk memungkinkannya menangani nama file dengan spasi dan karakter shell.-type
dan -name
adalah 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.-execdir
baris 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
$1
referensi 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..abc
nama 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: rename
opsi -n berguna. Itu menjalankan kering dan menunjukkan kepada Anda apa nama itu akan berubah, tetapi tidak membuat perubahan.
--execdir
tidak 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 mv
perintah. Saya memiliki banyak .3gp
file 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.3gp
menjadi file.3gp.mp4
, yang mungkin bukan yang diinginkan kebanyakan orang.
.3gp
atau .mp4
di sini hanya untuk tujuan ilustrasi.
basename "$i" .mp4
untuk 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 #1
di 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/' '{}' \;
-execdir
Opsi yang luar biasa melakukan a cd
ke dalam direktori sebelum mengeksekusi rename
perintah, 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 PATH
hacking diperlukan karena -execdir
memiliki satu kelemahan yang sangat mengganggu: find
yang sangat dogmatis dan menolak untuk melakukan apa saja dengan -execdir
jika Anda memiliki path relatif di Anda PATH
variabel 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?
-execdir
adalah ekstensi menemukan GNU ke POSIX . rename
berbasis Perl dan berasal dari rename
paket. 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 -execdir
dengan xargs
: https://superuser.com/questions/893890/xargs-change-working-directory-to-file-path-before-executing/915686
The sort -r
diperlukan untuk memastikan bahwa file datang setelah direktori masing-masing, karena jalur lagi datang setelah yang lebih pendek dengan awalan yang sama.