Saya berhasil dengan perintah ini.
rename JPG jpg *.JPG
Dimana rename
adalah perintah yang memberi tahu shell untuk mengganti nama setiap kemunculan JPG
ke jpg
di folder saat ini dengan semua nama file memiliki ekstensi JPG
.
Jika Anda melihat Bareword "JPG" tidak diizinkan saat "subs ketat" digunakan di (eval 1) baris 1 dengan pendekatan ini, coba:
rename 's/\.JPG$/.jpg/' *.JPG
Solusi
Anda dapat menyelesaikan tugas dalam satu baris:
find . -name '*.*' -exec sh -c '
a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/");
[ "$a" != "$0" ] && mv "$0" "$a" ' {} \;
Catatan:ini akan merusak nama file yang berisi baris baru. Tapi bersabarlah untuk saat ini.
Contoh penggunaan
$ mkdir C; touch 1.TXT a.TXT B.TXT C/D.TXT
$ find .
.
./C
./C/D.TXT
./1.TXT
./a.TXT
./B.TXT
$ find . -name '*.*' -exec sh -c 'a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/"); [ "$a" != "$0" ] && mv "$0" "$a" ' {} \;
$ find .
.
./C
./C/D.txt
./a.txt
./B.txt
./1.txt
Penjelasan
Anda menemukan semua file di direktori saat ini (.
) yang memiliki titik .
dalam namanya (-name '*.*'
) dan jalankan perintah untuk setiap file:
a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/");
[ "$a" != "$0" ] && mv "{}" "$a"
Perintah itu berarti:coba ubah ekstensi file menjadi huruf kecil (itu membuat sed
):
$ echo 1.txt | sed -r "s/([^.]*)\$/\L\1/"
1.txt
$ echo 2.TXT | sed -r "s/([^.]*)\$/\L\1/"
2.txt
dan simpan hasilnya ke a
variabel.
Jika ada yang diubah [ "$a" != "$0" ]
, ganti nama file mv "$0" "$a"
.
Nama file yang sedang diproses ({}
) diteruskan ke sh -c
sebagai argumen tambahan dan terlihat di dalam baris perintah sebagai $0
.Itu membuat skrip aman, karena dalam hal ini shell mengambil {} sebagai data, bukan sebagai bagian kode, seperti ketika ditetapkan langsung di baris perintah.(Terima kasih @gniourf_gniourf karena mengarahkan saya pada masalah yang sangat penting ini ).
Seperti yang Anda lihat, jika Anda menggunakan {}
langsung di skrip, dimungkinkan untuk memiliki beberapa injeksi shell di nama file, seperti:
; rm -rf * ;
Dalam hal ini injeksi akan dianggap oleh shell sebagai bagian dari kode dan akan dieksekusi.
Versi sementara
Versi skrip yang lebih jelas, tetapi sedikit lebih lama:
find . -name '*.*' | while IFS= read -r f
do
a=$(echo "$f" | sed -r "s/([^.]*)\$/\L\1/");
[ "$a" != "$f" ] && mv "$f" "$a"
done
Ini masih rusak untuk nama file yang berisi baris baru. Untuk memperbaiki masalah ini, Anda harus memiliki find
yang mendukung -print0
(seperti GNU find
) dan Bash (sehingga read
mendukung -d
sakelar pembatas):
find . -name '*.*' -print0 | while IFS= read -r -d '' f
do
a=$(echo "$f" | sed -r "s/([^.]*)\$/\L\1/");
[ "$a" != "$f" ] && mv "$f" "$a"
done
Ini masih rusak untuk file yang berisi baris baru (karena akan diserap oleh a=$(...)
subkulit. Jika Anda benar-benar ingin metode yang sangat mudah (dan Anda harus!), dengan versi Bash terbaru (Bash≥4.0) yang mendukung ,,
ekspansi parameter inilah solusi terbaiknya:
find . -name '*.*' -print0 | while IFS= read -r -d '' f
do
base=${f%.*}
ext=${f##*.}
a=$base.${ext,,}
[ "$a" != "$f" ] && mv -- "$f" "$a"
done
Kembali ke solusi awal
Atau dalam satu find
buka (kembali ke solusi asli dengan beberapa perbaikan yang membuatnya sangat mudah):
find . -name '*.*' -type f -exec bash -c 'base=${0%.*} ext=${0##*.} a=$base.${ext,,}; [ "$a" != "$0" ] && mv -- "$0" "$a"' {} \;
Saya menambahkan -type f
sehingga hanya file biasa yang diganti namanya. Tanpa ini, Anda masih dapat mengalami masalah jika nama direktori diganti sebelum nama file. Jika Anda juga ingin mengganti nama direktori (dan tautan, pipa, dll.), Anda harus menggunakan -depth
:
find . -depth -name '*.*' -type f -exec bash -c 'base=${0%.*} ext=${0##*.} a=$base.${ext,,}; [ "$a" != "$0" ] && mv -- "$0" "$a"' {} \;
sehingga find
melakukan penelusuran yang mengutamakan kedalaman.
Anda mungkin berpendapat bahwa menelurkan bash
tidaklah efisien proses untuk setiap file yang ditemukan. Itu benar, dan versi loop sebelumnya akan lebih baik.
Ini lebih pendek tetapi lebih umum, digabungkan dari jawaban orang lain:
rename 's/\.([^.]+)$/.\L$1/' *
Simulasi
Untuk simulasi, gunakan -n
, yaitu rename -n 's/\.([^.]+)$/.\L$1/' *
. Dengan cara ini Anda dapat melihat apa yang akan diubah sebelum perubahan nyata dilakukan. Contoh keluaran:
Happy.Family.GATHERING.JPG renamed as Happy.Family.GATHERING.jpg
Hero_from_The_Land_Across_the_River.JPG renamed as Hero_from_The_Land_Across_the_River.jpg
rAnD0m.jPg1 renamed as rAnD0m.jpg1
Penjelasan singkat tentang sintaks
- Sintaksnya adalah
rename OPTIONS 's/WHAT_TO_FIND_IN_THE_NAME/THE_REPLACEMENT/' FILENAMES
\.([^.]+)$
berarti urutan apa pun kecuali titik ([^.]
) di akhir string ($
), setelah titik (\.
).\L$1
berarti titik (\.
) diikuti dengan huruf kecil (\L
) dari 1 grup ($1
)- Grup pertama dalam hal ini adalah ekstensi (
[^.]+
) - Sebaiknya gunakan tanda kutip tunggal
'
bukannya tanda kutip ganda"
untuk membungkus regex untuk menghindari ekspansi shell