Bạn sẽ chạy trong một số vấn đề nếu bạn muốn đổi tên tập tin và thư mục cùng một lúc. Đổi tên chỉ là một tập tin là đủ dễ dàng. Nhưng bạn muốn chắc chắn rằng các thư mục cũng được đổi tên. Bạn không thể đơn giản mv Motörhead/Encöding Motorhead/Encoding
vì Motorhead
sẽ không tồn tại tại thời điểm cuộc gọi.
Vì vậy, chúng ta cần duyệt qua chiều sâu của tất cả các tệp và thư mục, sau đó chỉ đổi tên tệp hoặc thư mục hiện tại. Phần sau hoạt động với GNU find
và Bash 4.2.42 trên OS X của tôi.
#!/usr/bin/env bash
find "$1" -depth -print0 | while IFS= read -r -d '' file; do
d="$( dirname "$file" )"
f="$( basename "$file" )"
new="${f//[^a-zA-Z0-9\/\._\-]/}"
if [ "$f" != "$new" ] # if equal, name is already clean, so leave alone
then
if [ -e "$d/$new" ]
then
echo "Notice: \"$new\" and \"$f\" both exist in "$d":"
ls -ld "$d/$new" "$d/$f"
else
echo mv "$file" "$d/$new" # remove "echo" to actually rename things
fi
fi
done
Bạn có thể thay đổi regex bằng cách sử dụng new="${f//[\\\/\:\*\?\"<>|]/}"
nếu bạn muốn thay thế bất cứ điều gì Windows không thể xử lý.
Lưu tập lệnh này như rename.sh
, làm cho nó thực thi với chmod +x rename.sh
. Sau đó, gọi nó như thế nào rename.sh /some/path
.
Đảm bảo giải quyết mọi va chạm về tên tệp ( Notice
thông báo của Gabriel).
Nếu bạn hoàn toàn chắc chắn rằng nó thực hiện thay thế đúng, hãy xóa đoạn mã echo
khỏi tập lệnh để thực sự đổi tên mọi thứ thay vì chỉ in những gì nó làm.
Để an toàn, trước tiên tôi khuyên bạn nên thử nghiệm điều này trên một tập hợp nhỏ các tệp.
Tùy chọn giải thích
Để giải thích những gì diễn ra ở đây:
-depth
sẽ đảm bảo các thư mục được đệ quy theo chiều sâu, vì vậy chúng tôi có thể "cuộn" mọi thứ từ cuối. Thông thường, di find
chuyển khác nhau (nhưng không phải chiều rộng đầu tiên).
-print0
đảm bảo find
đầu ra là null được phân định, vì vậy chúng tôi có thể đọc nó bằng read -d ''
vào file
biến. Làm như vậy giúp chúng ta xử lý tất cả các loại tên tệp lạ, bao gồm cả tên có dấu cách và thậm chí cả dòng mới.
- Chúng tôi sẽ nhận được thư mục của tập tin với
dirname
. Đừng quên luôn luôn trích dẫn các biến của bạn một cách chính xác, nếu không, bất kỳ đường dẫn nào có khoảng trắng hoặc ký tự toàn cầu sẽ phá vỡ tập lệnh này.
- Chúng tôi sẽ nhận được tên tệp thực tế (hoặc tên thư mục) với
basename
.
- Sau đó, chúng tôi xóa bất kỳ ký tự không hợp lệ nào khỏi
$f
việc sử dụng các khả năng thay thế chuỗi của Bash. Không hợp lệ có nghĩa là bất cứ điều gì không phải là chữ thường hoặc chữ hoa, chữ số, dấu gạch chéo ( \/
), dấu chấm ( \.
), dấu gạch dưới hoặc dấu gạch nối.
- Nếu
$f
đã sạch (tên được làm sạch giống với tên hiện tại), hãy bỏ qua nó.
- Nếu
$new
đã tồn tại trong thư mục $d
(ví dụ: bạn có các tệp có tên resume
và résumé
trong cùng thư mục), hãy đưa ra cảnh báo. Bạn không muốn đổi tên nó, bởi vì, trên một số hệ thống, mv foo foo
gây ra sự cố. Nếu không thì,
- Cuối cùng chúng tôi đổi tên tập tin gốc (hoặc thư mục) thành tên mới của nó
Vì điều này sẽ chỉ hành động theo thứ bậc sâu nhất, nên việc đổi tên Motörhead/Encöding
thành Motorhead/Encoding
được thực hiện theo hai bước:
mv Motörhead/Encöding Motörhead/Encoding
mv Motörhead Motorhead
Điều này đảm bảo tất cả các thay thế được thực hiện theo đúng thứ tự.
Tệp ví dụ và chạy thử
Giả sử một số tệp trong thư mục cơ sở có tên test
:
test
test/Motörhead
test/Motörhead/anöther_file.mp3
test/Motörhead/Encöding
test/Randöm
test/Täst
test/Täst/Töst
test/with space
test/with-hyphen.txt
test/work
test/work/resume
test/work/résumé
test/work/schedule
Đây là đầu ra từ một lần chạy trong chế độ gỡ lỗi (với echo
phía trước mv
), tức là các lệnh sẽ được gọi và cảnh báo va chạm:
mv test/Motörhead/anöther_file.mp3 test/Motörhead/another_file.mp3
mv test/Motörhead/Encöding test/Motörhead/Encoding
mv test/Motörhead test/Motorhead
mv test/Randöm test/Random
mv test/Täst/Töst test/Täst/Tost
mv test/Täst test/Tast
mv test/with space test/withspace
Notice: "resume" and "résumé" both exist in test/work:
-rw-r—r-- … … test/work/resume
-rw-r—r-- … … test/work/résumé
Chú ý sự vắng mặt của các thông điệp cho with-hyphen.txt
, schedule
và test
chính nó.
mv
đã tồn tại, điều này có thể xảy ra (1) nếu bạn có các tệp đã sạch (kết quả làmv foo foo
) hoặc (2) nếu bạn có các tệp có cùng tên ngoại trừ cho các ký tự đặc biệt (ví dụ:mv Encöding Encoding
nơi bạn đã cóEncoding
tệp ngoàiEncöding
).