Turunkan semua direktori di bawah direktori


Jawaban:


10

Semua direktori pada satu level, atau secara rekursif?

Zsh

Pada satu tingkat:

autoload zmv
zmv -o-i -Q 'root/(*)(/)' 'root/${1:l}'

Secara rekursif:

zmv -o-i -Q 'root/(**/)(*)(/)' 'root/$1${2:l}'

Penjelasan: zmvmengganti nama file yang cocok dengan pola sesuai dengan teks pengganti yang diberikan. -o-imelewati -iopsi untuk setiap mvperintah di bawah tenda (lihat di bawah). Dalam teks pengganti, $1, $2, dll, adalah kelompok kurung berturut-turut dalam pola. **berarti semua (sub) * direktori, secara rekursif. Final (/)bukan grup kurung tetapi kualifikasi global yang berarti hanya cocok dengan direktori. ${2:l}dikonversi $2ke huruf kecil.

Portable

Pada satu tingkat:

for x in root/*/; do mv -i "$x" "$(printf %s "$x" | tr '[:upper:]' '[:lower:]')"; done

Final /membatasi pencocokan ke direktori, dan mv -imembuatnya meminta konfirmasi jika terjadi tabrakan. Hapus -iuntuk menimpa jika terjadi tabrakan, dan gunakan yes n | for …. untuk tidak diminta dan tidak melakukan penggantian nama yang akan bertabrakan.

Secara rekursif:

find root/* -depth -type d -exec sh -c '
    t=${0%/*}/$(printf %s "${0##*/}" | tr "[:upper:]" "[:lower:]");
    [ "$t" = "$0" ] || mv -i "$0" "$t"
' {} \;

Penggunaan -depthmemastikan bahwa direktori yang sangat bersarang diproses sebelum leluhur mereka. Pemrosesan nama bergantung pada ada /; jika Anda ingin memanggil operasi di direktori saat ini, gunakan ./*(mengadaptasi skrip shell untuk mengatasi .atau* dibiarkan sebagai latihan untuk pembaca).

Perl mengganti nama

Di sini saya menggunakan skrip rename Perl yang dikirimkan oleh Debian dan Ubuntu /usr/bin/prename(biasanya juga tersedia rename). Pada satu tingkat:

rename 's!/([^/]*/?)$!\L/$1!' root/*/

Secara rekursif, dengan bash ≥4 atau zsh:

shopt -s globstar  # only in bash
rename 's!/([^/]*/?)$!\L/$1!' root/**/*/

Secara rekursif, mudah dibawa:

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

Setidaknya pada OS X ini akan gagal jika ada direktori yang hurufnya lebih kecil: mv -i a aberi "mv: ganti nama a menjadi a / a: Argumen tidak valid".
— Janus

@ Janus: Benar, Anda mendapatkan pesan kesalahan, yang jelek (meskipun tidak berbahaya di baris perintah). Tapi bagaimanapun saya seharusnya menggunakan zmv, yang menangani kasus ini.
— Gilles 'SANGAT berhenti menjadi jahat'

Saya kemudian menemukan tentang -execdiryang luar biasa: unix.stackexchange.com/questions/5412/... Saya kemudian menemukan bahwa ia memiliki beberapa PATHkegilaan dan sedih :-(
— Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

4

Tidak ada satu perintah pun yang akan melakukan itu, tetapi Anda dapat melakukan sesuatu seperti ini:

for fd in */; do
  #get lower case version
  fd_lower=$(printf %s "$fd" | tr A-Z a-z)
  #if it wasn't already lowercase, move it.
  [ "$fd" != "$fd_lower" ] && mv "$fd" "$fd_lower"
done

Jika Anda ingin menjadi kuat, Anda harus memperhitungkan ketika sudah ada dua direktori yang hanya berbeda dalam kasus.

Sebagai one-liner:

for fd in */; do fd_lower=$(printf %s "$fd" | tr A-Z a-z) && [ "$fd" != "$fd_lower" ] && mv "$fd" "$fd_lower"; done

Ini muncul di tengah jalan melalui tulisan saya saran (pada dasarnya sama):for file in * ; do if [ -d "$file" ] ; then dest="$(echo $file | sed y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/)" ; [ "$dest" != "$file" ] && mv "$file" "$dest" ; fi ; done
— frabjous

Saya sedang berusaha menyelesaikannya find -type d, tetapi tidak bisa mendapatkannya
— Michael Mrozek

1
Insting saya seharusnya dilakukan for fd in */;, sehingga menghindari perlunya memeriksa apakah itu direktori, tapi saya tidak tahu apakah insting ini bagus.
— Steven D

Ya, untuk ... * / akan lebih baik.
— Shawn J. Goff

1
@Shawn: trsudah mengharapkan suatu range, sehingga tr '[A-Z]' '[a-z]'diterjemahkan [ke [dan ]untuk ]di lewat. Ini tidak berguna tetapi tidak berbahaya; namun tanpa tanda kutip shell akan memperluas tanda kurung jika ada file dengan nama satu huruf besar di direktori saat ini.
— Gilles 'SANGAT berhenti menjadi jahat'

0

Saya menganggap ini sebagai tantangan satu-lapis :) Pertama, buat uji kasus:

$ for d in foo Bar eVe; do mkdir -p dcthis/$d; touch dcthis/a${d}.txt; done
$ ls dcthis/
Bar     aBar.txt    aeVe.txt    afoo.txt    eVe     foo

Saya menggunakan finduntuk melihat direktori dengan huruf besar dan kemudian menurunkannya . Tebak menggunakan agak hack-ish, tapi kepalaku selalu meledak ketika aku mencoba melarikan diri secara langsung.sh -c 'mv {} echo {} | tr [:upper:] [:lower:]'sh -cfind

$ (cd dcthis && find . -maxdepth 1 -type d -path '*[A-Z]*' -exec sh -c 'mv {} `echo {} | tr [:upper:] [:lower:]`' \;)
$ ls dcthis/
aBar.txt    aeVe.txt    afoo.txt    bar     eve     foo

Berhati-hatilah: Solusi ini tidak memeriksa apakah downcasing mengarah ke tabrakan!


memeriksa tabrakan mudah: mv -i. Masalah yang lebih besar adalah bahwa Anda belum menggunakan kutipan yang tepat, sehingga perintah Anda akan gagal jika ada karakter khusus (spasi putih atau \[*?) di mana saja dalam nama. Tidak ada gunanya menggunakan findkecuali berulang, dan kemudian Anda perlu find -depth, dan -pathharus -name. Lihat jawaban saya untuk contoh kerja.
— Gilles 'SANGAT berhenti menjadi jahat'

@Giles. Terima kasih! Saya melihat Anda mv -isetelah menulis ini. Poin yang bagus dengan kutipan ...
— Janus

0

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/(.*)/\L$1/' '{}' \;

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

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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.