Найпростіший підхід - використовувати шар файлової системи для трансформації імен файлів. Починаючи з Ubuntu 12.04, існує файлова система FUSE, яка перетворює імена файлів в імена, які VFAT Windows підтримує: fuse-posixovl .
sudo mount.posixovl /media/sdb1
chown guillaume /media/sdb1
rsync -au ~/mail /media/sbd1/
Або щоб не вимагати кореневого доступу:
mkdir ~/mnt
/sbin/mount.posixovl -S /media/sdb1 ~/mnt
rsync -au ~/mail ~/mnt/
Символи в іменах файлів, VFAT не приймає кодуються як %(XX)
де XX
є шістнадцятиричні цифри. Станом на POSIXovl 1.2.20120215, майте на увазі, що ім’я файлу like %(3A)
кодується як саме, і буде розшифроване як :
, тому існує ризик зіткнення, якщо у вас є імена файлів, що містять підрядки форми %(XX)
.
Слідкуйте за тим, щоб POSIXovl не справлявся із занадто довгими іменами файлів. Якщо закодоване ім'я не вміщує 255 символів, файл не може бути збережений.
POSIXovl зберігає дозволи Unix та права власності у файлах, що називаються .pxovl.FILENAME
.
Наведений нижче скрипт bash ≥4 копіює ~/mail/foo:bar
у /media/usb99/mail/foo_bar
всі файли в ~/mail
. Файли, які вже існують у дереві призначення, і не старші за джерело, пропускаються.
#!/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
Цей скрипт працює під zsh з незначними модифікаціями: замінити shopt -s dotglob globstar
на setopt dot_glob
і [[ $target -ot $source ]]
на [[ ! -e $target || $target -ot $source ]]
.
Ось zsh-вкладиш zsh (три, якщо рахувати автозавантаження). Він коротший, але досить вдосконалений і не дуже читабельний.
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
Лінія еквівалентна mkdir -p ~/mail/**/*(…)
, за винятком того, що він не буде бомбити, якщо загальна довжина імен каталогів занадто довго. Цей рядок створює цільові каталоги в міру необхідності.
~/mail/**/*(/)
розширюється на всі каталоги в ~/mail
(каталоги лише завдяки (/)
кінці).
(/e\''…'\')
вибирає лише каталоги та надалі виконує код у межах "...", щоб перетворити кожне ім'я файлу, яке зберігається у REPLY
змінній.
${${REPLY#$HOME/}//:/_}
видаляє префікс, відповідний вихідному каталогу та перетворюється :
на _
.
zmv -C
копіює кожен файл, що відповідає його першому операнду (zsh візерунок) до імені файлу, отриманого шляхом розширенняg другого операнда.
-o -pu
каже перейти -pu
на cp
утиліту, щоб зберегти дозволи та скопіювати лише оновлені файли. (Ми могли б сказати zsh здійснити перевірку оновлення; це було б трохи швидше, але ще більш виразно.)
(.)
вибирає лише звичайні файли. -Q
говорить, що це слід аналізувати як глобальний класифікатор, а не як .
круглі дужки навколо нього, що вказує на піддекспресію.
$1
а $2
в тексті заміни відповідають збіг у дужках (**/)
і *
. ( **
втрачає своє особливе значення як нульовий або більше рівнів підкаталогів, якщо він знаходиться в дужках, якщо дужки не містять точно **/
.)
Спочатку я думав використовувати pax , який є інструментом архівування (тут призначений для використання в режимі проходження), який має функцію перейменування файлів (його -s
опція). Однак -s
і -u
параметри не працюють разом ( визначення POSIX pax буквально говорить про те, що -u
необхідно перевірити файл з тим самим іменем у дереві призначення, а не ім'я файлу, перетворене -s
; реалізація pax в Ubuntu дотримується специфікації буквально, а не корисно). Ще можна скористатися ним, щоб зробити перейменовані жорсткі посилання, а потім скопіювати жорсткі посилання (з rsync -au
або pax -rw -pp -u
) на інші носії, але це відчуває більше проблем, ніж це варто.
cd ~/mail
mkdir -p /media/usb99/mail
pax -rw -l -pp -s '!:!_!g' . ../mail.colonless
rsync -au ../mail.colonless/ /media/usb99/mail/