Câu trả lời:
Tất cả các thư mục ở một cấp độ, hoặc đệ quy?
Ở một cấp độ:
autoload zmv
zmv -o-i -Q 'root/(*)(/)' 'root/${1:l}'
Đệ quy:
zmv -o-i -Q 'root/(**/)(*)(/)' 'root/$1${2:l}'
Giải thích: zmvđổi tên các tệp khớp với mẫu theo văn bản thay thế đã cho. -o-ichuyển -itùy chọn cho mỗi mvlệnh dưới mui xe (xem bên dưới). Trong văn bản thay thế, $1, $2, vv, là những nhóm trong ngoặc đơn liên tiếp trong mẫu. **có nghĩa là tất cả các thư mục (phụ) *, đệ quy. Trận chung kết (/)không phải là một nhóm được ngoặc đơn mà là một vòng loại toàn cầu có nghĩa là chỉ khớp với các thư mục. ${2:l}chuyển đổi $2thành chữ thường.
Ở một cấp độ:
for x in root/*/; do mv -i "$x" "$(printf %s "$x" | tr '[:upper:]' '[:lower:]')"; done
Cuối cùng /hạn chế sự phù hợp với các thư mục và mv -ilàm cho nó yêu cầu xác nhận trong trường hợp va chạm. Hủy bỏ -iđể ghi đè trong trường hợp va chạm và sử dụng yes n | for …. không được nhắc và không thực hiện bất kỳ đổi tên nào sẽ va chạm.
Đệ quy:
find root/* -depth -type d -exec sh -c '
t=${0%/*}/$(printf %s "${0##*/}" | tr "[:upper:]" "[:lower:]");
[ "$t" = "$0" ] || mv -i "$0" "$t"
' {} \;
Việc sử dụng -depthđảm bảo rằng các thư mục lồng nhau sâu được xử lý trước tổ tiên của chúng. Việc xử lý tên dựa vào đó là một /; nếu bạn muốn gọi hoạt động trong thư mục hiện tại, hãy sử dụng ./*(điều chỉnh kịch bản shell để đối phó .hoặc *để lại như một bài tập cho người đọc).
Ở đây tôi sử dụng tập lệnh đổi tên Perl mà Debian và Ubuntu /usr/bin/prenamecung cấp (thường cũng có sẵn rename). Ở một cấp độ:
rename 's!/([^/]*/?)$!\L/$1!' root/*/
Đệ quy, với bash ≥4 hoặc zsh:
shopt -s globstar # only in bash
rename 's!/([^/]*/?)$!\L/$1!' root/**/*/
Đệ quy, di chuyển:
find root -depth -type d -exec rename -n 's!/([^/]*/?)$!\L/$1!' {} +
-execdirmà là awesome: unix.stackexchange.com/questions/5412/... tôi sau đó phát hiện ra rằng nó có một số PATHđiên rồ và rất buồn :-(
Không có một lệnh nào sẽ làm điều đó, nhưng bạn có thể làm một cái gì đó như thế này:
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
Nếu bạn cần nó mạnh mẽ, bạn nên tính đến khi đã có hai thư mục chỉ khác nhau trong trường hợp.
Như một lớp lót:
for fd in */; do fd_lower=$(printf %s "$fd" | tr A-Z a-z) && [ "$fd" != "$fd_lower" ] && mv "$fd" "$fd_lower"; done
for file in * ; do if [ -d "$file" ] ; then dest="$(echo $file | sed y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/)" ; [ "$dest" != "$file" ] && mv "$file" "$dest" ; fi ; done
find -type d, nhưng không thể hiểu được
for fd in */;, do đó tránh sự cần thiết phải kiểm tra nếu đó là một thư mục, nhưng tôi không biết bản năng này có phải là một thứ tốt hay không.
trđã hy vọng một phạm vi, vì vậy tr '[A-Z]' '[a-z]'dịch [đến [và ]để ]trong đi qua. Điều này là vô ích nhưng vô hại; tuy nhiên không có dấu ngoặc kép, shell sẽ mở rộng dấu ngoặc nếu có một tệp có tên một chữ cái in hoa trong thư mục hiện tại.
Tôi đã coi đây là một thử thách một lót :) Đầu tiên, hãy thiết lập một trường hợp thử nghiệm:
$ 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
Tôi sử dụng findđể phát hiện các thư mục với các chữ cái viết hoa và sau đó viết thường chúng . Đoán sử dụng là một chút hack-ish, nhưng đầu tôi luôn nổ tung khi tôi cố gắng thoát khỏi mọi thứ trực tiếp.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
Được cảnh báo: Giải pháp này không kiểm tra xem việc hạ xuống có dẫn đến va chạm hay không!
mv -i. Một vấn đề lớn hơn là bạn chưa sử dụng trích dẫn thích hợp, vì vậy lệnh của bạn sẽ thất bại nếu có các ký tự đặc biệt (khoảng trắng hoặc \[*?) ở bất kỳ đâu trong tên. Không có điểm sử dụng findtrừ khi đệ quy, và sau đó bạn cần find -depth, và -pathphải -name. Xem câu trả lời của tôi cho các ví dụ làm việc.
mv -isau khi viết này. Điểm hay với trích dẫn ...
find -execdir| đổi tên
Đây sẽ là cách tốt nhất để làm điều đó nếu nó không vì sự điên rồ của đường dẫn tương đối, vì nó tránh cho Perl regex fu chỉ hành động trên tên cơ sở:
PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
find a -depth -execdir rename 's/(.*)/\L$1/' '{}' \;
-execdirđầu tiên cdvào thư mục trước khi chỉ thực hiện trên tên cơ sở.
Thật không may, tôi không thể thoát khỏi PATHphần hack đó , find -execdirtừ chối làm bất cứ điều gì nếu bạn có một đường dẫn tương đối trong PATH...: https://askubfox.com/questions/621132/why-USE-the-execdir-action- is-insecure-for-thư mục-which-is-in-the-path / 1109378 # 1109378
mv -i a ađưa ra "mv: đổi tên a thành a / a: Đối số không hợp lệ".