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.