Pendekatan yang paling mudah adalah dengan memanfaatkan lapisan sistem file untuk mengubah nama file. Sejak Ubuntu 12.04, ada sistem file FUSE yang mengubah nama file menjadi nama yang didukung oleh VFAT Windows: fuse-posixovl .
sudo mount.posixovl /media/sdb1
chown guillaume /media/sdb1
rsync -au ~/mail /media/sbd1/
Atau untuk menghindari memerlukan akses root:
mkdir ~/mnt
/sbin/mount.posixovl -S /media/sdb1 ~/mnt
rsync -au ~/mail ~/mnt/
Karakter dalam nama file yang tidak diterima VFAT dikodekan sebagai di %(XX)
mana XX
digit heksadesimal. Pada POSIXovl 1.2.20120215, berhati-hatilah bahwa nama file seperti %(3A)
dikodekan sebagai dirinya sendiri, dan akan diterjemahkan sebagai :
, sehingga ada risiko tabrakan jika Anda memiliki nama file yang mengandung substring formulir %(XX)
.
Berhati-hatilah karena POSIXovl tidak mengatasi nama file yang terlalu panjang. Jika nama yang disandikan tidak muat dalam 255 karakter, file tidak dapat disimpan.
POSIXovl menyimpan izin dan kepemilikan unix dalam file yang dipanggil .pxovl.FILENAME
.
Bash ≥4 salinan skrip berikut ~/mail/foo:bar
untuk /media/usb99/mail/foo_bar
, dan juga untuk semua file di bawah ~/mail
. File yang sudah ada di pohon tujuan dan yang tidak lebih tua dari sumber dilewati.
#!/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
Skrip ini berfungsi di bawah zsh dengan modifikasi kecil: ganti shopt -s dotglob globstar
dengan setopt dot_glob
dan [[ $target -ot $source ]]
oleh [[ ! -e $target || $target -ot $source ]]
.
Berikut ini adalah zsh two-liner (tiga jika Anda menghitung autoloads). Ini lebih pendek, tetapi cukup maju dan tidak terlalu mudah dibaca.
autoload zargs zmv
zargs -- ~/mail/**/*(/e\''REPLY=/media/usb99/${${REPLY#$HOME/}//:/_}'\') -- mkdir -p --
zmv -C -Q -o -pu '~/mail/(**/)(*)(.)' '/media/usb99/mail/${1//:/_}${2//:/_}'
- The
zargs
garis setara dengan mkdir -p ~/mail/**/*(…)
, kecuali bahwa ia tidak akan mengebom keluar jika panjang kumulatif dari nama direktori terlalu panjang. Baris itu menciptakan direktori target seperlunya.
~/mail/**/*(/)
memperluas ke semua direktori di bawah ~/mail
(direktori hanya karena (/)
pada akhir).
(/e\''…'\')
hanya memilih direktori dan selanjutnya mengeksekusi kode dalam '...' untuk mengubah setiap nama file, yang disimpan dalam REPLY
variabel.
${${REPLY#$HOME/}//:/_}
menghapus awalan yang sesuai dengan direktori sumber dan mengubahnya :
menjadi _
.
zmv -C
menyalin setiap file yang cocok dengan operan pertamanya (pola zsh) ke nama file yang diperoleh dengan memperluas operan keduanya.
-o -pu
mengatakan untuk meneruskan -pu
ke cp
utilitas, sehingga dapat mempertahankan izin dan hanya menyalin file yang diperbarui. (Kami dapat memberi tahu zsh untuk melakukan pemeriksaan pembaruan; itu akan menjadi sedikit lebih cepat tetapi bahkan lebih samar.)
(.)
hanya memilih file biasa. -Q
mengatakan bahwa ini harus diurai sebagai kualifikasi glob dan bukan sebagai .
dengan tanda kurung di sekitarnya yang menunjukkan subekspresi.
$1
dan $2
dalam teks pengganti cocok dengan tanda kurung (**/)
dan *
. ( **
kehilangan arti khusus sebagai nol atau lebih tingkat subdirektori jika dalam tanda kurung, kecuali tanda kurung mengandung persis **/
.)
Saya awalnya berpikir untuk menggunakan pax , yang merupakan alat pengarsipan (di sini dimaksudkan untuk digunakan dalam mode pass-through) yang memiliki fitur pengubahan nama file ( -s
opsinya). Namun, opsi -s
dan -u
tidak bekerja bersama-sama ( definisi POSIX dari pax secara harfiah mengatakan bahwa -u
harus memeriksa file dengan nama yang sama di pohon tujuan, daripada nama file yang diubah oleh -s
; implementasi pax di Ubuntu mengikuti spesifikasi secara harfiah daripada berguna). Masih mungkin untuk memanfaatkannya untuk membuat tautan keras yang diganti namanya, dan kemudian menyalin tautan keras itu (dengan rsync -au
atau pax -rw -pp -u
) ke media lain, tetapi rasanya lebih banyak masalah daripada nilainya.
cd ~/mail
mkdir -p /media/usb99/mail
pax -rw -l -pp -s '!:!_!g' . ../mail.colonless
rsync -au ../mail.colonless/ /media/usb99/mail/