GNU/Linux >> Belajar Linux >  >> Linux

Konversikan semua ekstensi file menjadi huruf kecil

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

Linux
  1. Hapus Semua File/direktori Kecuali Satu File?

  2. Bagaimana Cara Membersihkan Ekstensi File?

  3. Tampilkan Semua File Hingga Pertandingan?

  1. Cara mengonversi file teks ke semua huruf besar atau kecil

  2. tautan simbolik:temukan semua file yang terhubung ke file ini

  3. Tulis ke file .txt?

  1. Redirect semua output ke file menggunakan Bash di Linux?

  2. Mengubah semua ekstensi file dalam folder menggunakan CLI di Linux

  3. Ubah .txt menjadi .csv di shell