Cách tiếp cận đơn giản nhất là tận dụng lớp hệ thống tập tin để chuyển đổi tên tệp. Kể từ Ubuntu 12.04, có một hệ thống tệp FUSE chuyển đổi tên tệp thành tên mà VFAT của Windows hỗ trợ: fuse-posixovl .
sudo mount.posixovl /media/sdb1
chown guillaume /media/sdb1
rsync -au ~/mail /media/sbd1/
Hoặc để tránh yêu cầu quyền truy cập root:
mkdir ~/mnt
/sbin/mount.posixovl -S /media/sdb1 ~/mnt
rsync -au ~/mail ~/mnt/
Ký tự trong tên tập tin đó VFAT không chấp nhận được mã hóa như %(XX)
nơi XX
là hexadecimal chữ số. Kể từ POSIXovl 1.2.20120215, hãy cẩn thận rằng tên tệp giống như %(3A)
được mã hóa và sẽ được giải mã :
, do đó, có nguy cơ xảy ra xung đột nếu bạn có tên tệp chứa chuỗi con của biểu mẫu %(XX)
.
Coi chừng POSIXovl không đối phó với tên tệp quá dài. Nếu tên được mã hóa không khớp với 255 ký tự, tệp không thể được lưu trữ.
POSIXovl lưu trữ các quyền unix và quyền sở hữu trong các tệp được gọi .pxovl.FILENAME
.
Các bash sau ≥4 bản sao kịch bản ~/mail/foo:bar
để /media/usb99/mail/foo_bar
, và tương tự cho tất cả các file dưới ~/mail
. Các tệp đã tồn tại trong cây đích và không cũ hơn nguồn được bỏ qua.
#!/bin/bash
set -e
shopt -s dotglob globstar
for source in "$HOME"/mail/**/*; do
target=/media/usb99/${source#"$HOME"/}
target=${target//:/_}
if [[ -d $source ]]; then
mkdir -p -- "$target"
elif [[ $target -ot $source ]]; then
cp -p -- "$source" "$target"
fi
done
Kịch bản này hoạt động theo zsh với các sửa đổi nhỏ: thay thế shopt -s dotglob globstar
bằng setopt dot_glob
và [[ $target -ot $source ]]
bởi [[ ! -e $target || $target -ot $source ]]
.
Đây là một lớp lót hai lớp zsh (ba nếu bạn đếm số lần tự động tải). Nó ngắn hơn, nhưng khá tiên tiến và không dễ đọc.
autoload zargs zmv
zargs -- ~/mail/**/*(/e\''REPLY=/media/usb99/${${REPLY#$HOME/}//:/_}'\') -- mkdir -p --
zmv -C -Q -o -pu '~/mail/(**/)(*)(.)' '/media/usb99/mail/${1//:/_}${2//:/_}'
- Các
zargs
dòng là tương đương với mkdir -p ~/mail/**/*(…)
, ngoại trừ việc nó sẽ không đánh bom ra nếu chiều dài tích lũy trong những cái tên thư mục quá dài. Dòng đó tạo các thư mục đích khi cần thiết.
~/mail/**/*(/)
mở rộng đến tất cả các thư mục bên dưới ~/mail
(chỉ thư mục do (/)
ở cuối).
(/e\''…'\')
chỉ chọn các thư mục và tiếp tục thực thi mã trong '' 'để chuyển đổi từng tên tệp được lưu trữ trong REPLY
biến.
${${REPLY#$HOME/}//:/_}
loại bỏ tiền tố tương ứng với thư mục nguồn và thay đổi :
thành _
.
zmv -C
sao chép từng tệp khớp với toán hạng đầu tiên của nó (mẫu zsh) vào tên tệp thu được bằng cách mở rộng toán hạng thứ hai của nó.
-o -pu
nói để chuyển -pu
đến cp
tiện ích, để giữ quyền và chỉ sao chép các tệp đã cập nhật. (Chúng tôi có thể yêu cầu zsh thực hiện kiểm tra cập nhật; nó sẽ nhanh hơn một chút nhưng thậm chí còn khó hiểu hơn.)
(.)
chỉ chọn các tập tin thông thường. -Q
nói rằng điều này sẽ được phân tích cú pháp như một vòng loại toàn cầu chứ không phải là .
dấu ngoặc đơn xung quanh nó biểu thị một biểu thức con.
$1
và $2
trong văn bản thay thế khớp với các biểu thức được ngoặc đơn (**/)
và *
. ( **
mất ý nghĩa đặc biệt của nó là 0 hoặc nhiều cấp thư mục con nếu nó nằm trong ngoặc đơn, trừ khi dấu ngoặc đơn chứa chính xác **/
.)
Ban đầu tôi nghĩ sử dụng pax , một công cụ lưu trữ (ở đây dự định sẽ được sử dụng trong chế độ chuyển qua) có tính năng đổi tên tệp ( -s
tùy chọn của nó ). Tuy nhiên, các tùy chọn -s
và -u
không hoạt động cùng nhau ( định nghĩa POSIX của pax theo nghĩa đen nói rằng -u
phải kiểm tra một tệp cùng tên trong cây đích, thay vì tên tệp được chuyển đổi bởi -s
; việc triển khai pax trong Ubuntu theo đúng nghĩa đen hơn là hữu ích). Vẫn có thể sử dụng nó để đổi tên các liên kết cứng và sau đó sao chép các liên kết cứng (có rsync -au
hoặc pax -rw -pp -u
) sang các phương tiện khác, nhưng nó cảm thấy rắc rối hơn giá trị của nó.
cd ~/mail
mkdir -p /media/usb99/mail
pax -rw -l -pp -s '!:!_!g' . ../mail.colonless
rsync -au ../mail.colonless/ /media/usb99/mail/