Bagaimana saya bisa menggunakan rename untuk mengubah nama everyting menjadi huruf besar secara rekursif

11

Saya ingin mengubah nama semua file dan folder (sub-folder) secara rekursif menjadi huruf besar.

Saya menemukan beberapa skrip yang akan melakukannya menjadi huruf kecil, tetapi saya tidak tahu bagaimana mengubahnya sehingga akan melakukannya sebaliknya (lebih rendah ke atas).

Skrip yang saya temukan dan berfungsi untuk huruf kecil, tetapi saya tidak tahu cara memodifikasi adalah:

rename 'y/A-Z/a-z/' *

Itu dari man rename.

jnhghy - Alexandru Jantea
sumber
Tanpa mengetahui apa pun tentang perintah rename, saya curiga bahwa jika Anda mencoba, rename 'y/a-z/A-Z/' *Anda akan mendapatkan apa yang Anda inginkan. Hati-hati saat Anda mengujinya.
Warwick
itu tidak secara berulang (karena yang pertama tidak ...) tetapi berhasil. Saya tidak bisa mengerti mengapa saya tidak menyalahkan :) :)
jnhghy - Alexandru Jantea
Saya pikir mengingat kualitas jawaban Gilles, itu akan baik jika Anda menerima jawabannya sebagai pilihan saya. Ini jauh lebih lengkap daripada milik saya dan menjelaskan pilihan Anda (dan bagaimana semuanya bekerja). Terima kasih.
Warwick,

Jawaban:

8

Perhatikan bahwa Anda menggunakan skrip Perl yang disebutrename didistribusikan oleh Debian dan turunannya (Ubuntu, Mint, ...). Distribusi Linux lainnya mengirimkan perintah yang sama sekali berbeda, dan sangat tidak berguna, disebut rename.

y/A-Z/a-z/menerjemahkan setiap karakter dalam kisaran Amelalui Zke dalam sesuai karakter dalam kisaran amelalui z, yaitu ASCII huruf besar huruf ke huruf kecil yang sesuai. Untuk melakukan terjemahan yang berlawanan, gunakan y/a-z/A-Z/. Cara lain untuk menulis perintah yang sama adalah rename '$_ = uc($_)' *ucadalah fungsi u pper c ase, dan renameperintah mengganti nama file berdasarkan transformasi yang dibuat ke $_variabel.

rename '…' *hanya mengganti nama file di direktori saat ini, karena itulah yang *cocok. File dot (file yang namanya dimulai dengan .) dilewati juga.

Jika Anda ingin mengganti nama file di direktori saat ini dan di subdirektori secara rekursif, Anda dapat menggunakan findperintah untuk melintasi direktori saat ini secara rekursif. Ada kesulitan di sini: jika Anda menelepon rename, ini mengganti nama direktori dan bagian nama dasar. Jika Anda memanggil renamedirektori sebelum berulang ke dalamnya ( find -exec rename … {} \;), findmenjadi bingung karena menemukan direktori tetapi direktori itu tidak ada lagi pada saat ia mencoba turun ke dalamnya. Anda bisa menyiasatinya dengan mengatakan finduntuk melintasi direktori sebelum bertindak di atasnya, tapi kemudian Anda berakhir mencoba untuk mengubah nama foo/barke FOO/BARtetapi direktori FOOtidak ada.

Cara sederhana untuk menghindari kesulitan ini adalah membuat perintah pengubahan nama hanya bertindak pada bagian nama dasar dari path. Ekspresi reguler ([^/]*\Z)cocok dengan bagian akhir dari jalur yang tidak mengandung a /.

find . -depth -exec rename 's!([^/]*\Z)!uc($1)!e' {} +

Shell zsh menyediakan fitur yang lebih nyaman untuk penggantian nama - bahkan lebih samar dari Perl, tetapi lebih singkat dan seringkali lebih mudah untuk dikomposisi.

Fungsi zmvmengubah nama file berdasarkan pola. Jalankan autoload -U zmvsekali untuk mengaktifkannya (masukkan baris ini di Anda .zshrc).

Dalam argumen pertama ke zmv(pola untuk mengganti), Anda dapat menggunakan pola wildcard zsh yang kuat . Dalam argumen kedua ke zmv(teks pengganti), Anda dapat menggunakan fitur ekspansi parameternya , termasuk pengubah riwayat .

zmv -w '**/*' '$1$2:u'

Penjelasan:

  • -w - Otomatis menetapkan variabel numerik untuk setiap pola wildcard
  • **/*- semua file dalam subdirektori, secara rekursif ( **/cocok dengan 0, 1 atau lebih level subdirektori)
  • $1 - variabel numerik pertama, di sini cocok dengan bagian direktori dari setiap jalur
  • $2:u- variabel numerik kedua, di sini mencocokkan bagian nama dasar dari setiap jalur, dengan :upengubah untuk mengkonversi nilai menjadi huruf besar

Sebagai bonus tambahan, ini menghormati pengaturan lokal sekitar.

Jika Anda tidak yakin tentang zmvperintah yang Anda tulis, Anda dapat memberikan -nopsi untuk mencetak apa yang akan dilakukan perintah dan tidak mengubah apa pun. Periksa output, dan jika itu melakukan apa yang Anda inginkan, jalankan kembali perintah tanpa -nbenar-benar bertindak.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
5

Dicuri (dengan suntingan kecil) dari posting Gilles di sini

find <DIR> -depth -type d -exec rename -n 's!/([^/]*/?)$!\U/$1!' {} +

Warwick
sumber
Ini tidak bertindak secara rekursif.
Gilles 'SO- berhenti bersikap jahat'
Benar. Seharusnya saya membaca pertanyaan dengan benar. Saya tidak memiliki akses ke perintah ganti nama, tetapi saya yakin ini akan bekerja secara rekursif -find <dir> -exec rename 'y/a-z/A-Z/' {} \;
Warwick
Ini sedikit lebih rumit dari itu, karena Anda mengganti nama direktori ketika findsedang berulang ke dalamnya.
Gilles 'SO- berhenti bersikap jahat'
@Gilles - Oke. Setelah melakukan sedikit riset, tampaknya saya perlu menambahkan opsi -depth untuk menemukan agar nama direktori ditangani terakhir. Jadi find <dir> -depth -exec rename 'y/a-z/A-Z/' {} \;harus menangani masalah penggantian nama direktori. Benar?
Warwick
Tidak, itu masih tidak berhasil, karena renameperubahan misalnya foo/barke FOO/BARdan FOOtidak ada pada saat itu.
Gilles 'SO- berhenti bersikap jahat'
2

Saya ingin mengarahkan siapa pun yang masih terkait dengan jawaban ini ke jawaban luar biasa yang diberikan Guiles Quernot untuk pertanyaan ini yang tidak diperlukan find.

Perintah yang dihasilkan adalah:

shopt -s globstar
rename -n 'y/a-z/A-Z/' **

Tetapi sebelum menjalankan silakan baca jawaban yang terhubung untuk peringatan tentang versi bash lama.

Akhirnya kalau-kalau ada yang bertanya-tanya apa yang dilakukan y///perintah perl regex. Berikut tautan ke dokumentasi yang relevan .

Marcelo Lacerda
sumber
1

find -execdir| ganti nama

Ini akan menjadi cara terbaik untuk melakukannya jika bukan karena kegilaan jalur relatif, karena ia menghindari Perl regex fu untuk hanya bertindak berdasarkan nama:

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

-execdirpertama-tama cdmasuk ke direktori sebelum mengeksekusi hanya pada nama bas.

Sayangnya, saya tidak dapat menyingkirkan PATHbagian peretasan itu, find -execdirmenolak melakukan apa pun jika Anda memiliki jalur relatif di PATH...: /ubuntu/621132/why-using-the-execdir-action- is-insecure-for-direktori-which-is-in-the-path / 1109378 # 1109378

Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功
sumber
0

Coba ini setelah pindah ke direktori tempat Anda ingin mengganti nama file:

for word in `ls -ltr |tail -n +2 |awk '{print $9}'`
do
  a=$(echo $word | tr '[a-z]' '[A-Z]')
  mv $word $a
  echo "Done Successfully"
done
Sorav
sumber
Jangan parsing output ls (dan mengapa Anda ls -lhanya menjalankan untuk memotong kolom selain nama?), Dan menggunakan tanda kutip ganda di sekitar substitusi variabel . Kode Anda terlalu rumit dan terpecah pada nama file yang mengandung spasi dan karakter khusus lainnya. Gunakan findatau **/untuk kembali ke subdirektori, output lshanya untuk konsumsi manusia.
Gilles 'SO- berhenti bersikap jahat'