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 XX
onaltı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:bar
iç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 globstar
göre setopt dot_glob
ve [[ $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 REPLY
değ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 -pu
izinleri korumak ve yalnızca güncellenmiş dosyaları kopyalamak -pu
için cp
yardı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. -Q
bunun, .
bir alt ifadeyi gösteren parantez içinde değil, bir glob niteleyicisi olarak ayrıştırılacağını söylüyor .
$1
ve $2
değ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 -s
ve -u
seç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 -au
veya 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/