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-i
chuyển -i
tùy chọn cho mỗi mv
lệ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 $2
thà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 -i
là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/prename
cung 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!' {} +
-execdir
mà 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 -c
find
$ (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 find
trừ khi đệ quy, và sau đó bạn cần find -depth
, và -path
phải -name
. Xem câu trả lời của tôi cho các ví dụ làm việc.
mv -i
sau 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 cd
và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 PATH
phần hack đó , find -execdir
từ 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ệ".