En basit yaklaşım, dosya adlarını dönüştürmek için dosya sistemi katmanından yararlanmaktır. Ubuntu 12.04'ten beri, dosya adlarını Windows VFAT'in desteklediği adlara dönüştüren bir FUSE dosya sistemi var: fuse-posixovl
.
sudo mount.posixovl /media/sdb1
chown guillaume /media/sdb1
rsync -au ~/mail /media/sbd1/
Veya root erişimi gerektirmekten kaçınmak için:
mkdir ~/mnt
/sbin/mount.posixovl -S /media/sdb1 ~/mnt
rsync -au ~/mail ~/mnt/
VFAT kabul etmediğini dosya adlarında karakterler olarak kodlanmıştır %(XX)nerede XXonaltılık basamak vardır. POSIXovl 1.2.20120215'ten itibaren, gibi bir dosya adının %(3A)kendisinin kodlandığı ve kodunun çözüleceğine dikkat edin :, bu nedenle formun alt dizelerini içeren dosya adlarınız varsa çarpışma riski vardır %(XX).
POSIXovl'un çok uzun dosya adlarıyla başa çıkmadığına dikkat edin. Kodlanan ad 255 karaktere sığmıyorsa, dosya kaydedilemez.
POSIXovl, unix izinlerini ve sahipliğini çağrılan dosyalarda saklar .pxovl.FILENAME.
Aşağıdaki bash ≥4 komut dosyası kopyaları ~/mail/foo:bariçin /media/usb99/mail/foo_bar, ve benzer altındaki tüm dosyalar için ~/mail. Hedef ağaçta zaten var olan ve kaynaktan daha eski olmayan dosyalar atlanır.
#!/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
Bu komut dosyası küçük modifikasyonlarla zsh altında çalışır: yerine shopt -s dotglob globstargöre setopt dot_globve [[ $target -ot $source ]]tarafından [[ ! -e $target || $target -ot $source ]].
İşte bir zsh iki astar (otomatik yükleri sayarsanız üç). Daha kısa, ancak oldukça gelişmiş ve çok okunabilir değil.
autoload zargs zmv
zargs -- ~/mail/**/*(/e\''REPLY=/media/usb99/${${REPLY#$HOME/}//:/_}'\') -- mkdir -p --
zmv -C -Q -o -pu '~/mail/(**/)(*)(.)' '/media/usb99/mail/${1//:/_}${2//:/_}'
zargsÇizgi eşdeğerdir mkdir -p ~/mail/**/*(…)dizin adlarının kümülatif uzunluğu çok uzun ise dışarı bomba olmaz dışında. Bu satır, gerektiği şekilde hedef dizinleri oluşturur.
~/mail/**/*(/)altındaki tüm dizinlere genişler ~/mail(sadece (/)sondaki dizinler nedeniyle ).
(/e\''…'\')yalnızca dizinleri seçer ve REPLYdeğişkende saklanan her dosya adını dönüştürmek için '…' içindeki kodu çalıştırır .
${${REPLY#$HOME/}//:/_}kaynak dizin ve değişiklikler ile ilgili önek kaldırır :içine _.
zmv -C ilk işleneniyle (zsh deseni) eşleşen her dosyayı ikinci işlenenini genişleterek elde edilen dosya adına kopyalar.
-o -puizinleri korumak ve yalnızca güncellenmiş dosyaları kopyalamak -puiçin cpyardımcı programa geçmeyi söylüyor . (Zsh'ye güncelleme kontrolünü yapmasını söyleyebiliriz; biraz daha hızlı ama daha şifreli olurdu.)
(.)yalnızca normal dosyaları seçer. -Qbunun, .bir alt ifadeyi gösteren parantez içinde değil, bir glob niteleyicisi olarak ayrıştırılacağını söylüyor .
$1ve $2değiştirilen metinde parantez içindeki ifadelerle eşleşir (**/)ve *. ( **parantez tam olarak belirtilmedikçe, parantez içinde ise özel anlamını sıfır veya daha fazla alt dizin düzeyi olarak kaybeder **/.)
Başlangıçta bir dosya yeniden adlandırma özelliği ( seçenek) olan bir arşivleme aracı (burada geçiş modunda kullanılmak üzere tasarlanmıştır) olan pax kullanmayı düşündüm -s. Ancak -sve -useçenekleri birlikte çalışmaz ( pax'un POSIX tanımı,-u dönüştürülen dosya adından ziyade aynı adda bir dosyayı hedef ağaçta kontrol etmesi gerektiğini söyler -s; Ubuntu'daki pax uygulaması, tam anlamıyla faydalı bir şekilde). Yeniden adlandırılmış sabit bağlantılar yapmak ve bundan sonra sabit bağlantıları ( rsync -auveya ile pax -rw -pp -u) diğer medyaya kopyalamak için kullanmak hala mümkündür , ancak değerinden daha fazla sorun çıkarır.
cd ~/mail
mkdir -p /media/usb99/mail
pax -rw -l -pp -s '!:!_!g' . ../mail.colonless
rsync -au ../mail.colonless/ /media/usb99/mail/