L'approche la plus simple consiste à tirer parti de la couche du système de fichiers pour transformer les noms de fichiers. Depuis Ubuntu 12.04, il existe un système de fichiers FUSE qui transforme les noms de fichiers en noms pris en charge par le VFAT de Windows: fuse-posixovl .
sudo mount.posixovl /media/sdb1
chown guillaume /media/sdb1
rsync -au ~/mail /media/sbd1/
Ou pour éviter d'exiger un accès root:
mkdir ~/mnt
/sbin/mount.posixovl -S /media/sdb1 ~/mnt
rsync -au ~/mail ~/mnt/
Les caractères dans les noms de fichiers que VFAT n'accepte pas sont codés comme %(XX)
où XX
sont les chiffres hexadécimaux. À partir de POSIXovl 1.2.20120215, sachez qu'un nom de fichier comme %(3A)
est codé comme lui-même et sera décodé en tant que :
, il y a donc un risque de collision si vous avez des noms de fichiers contenant des sous-chaînes du formulaire %(XX)
.
Attention, POSIXovl ne gère pas les noms de fichiers trop longs. Si le nom codé ne tient pas en 255 caractères, le fichier ne peut pas être stocké.
POSIXovl stocke les autorisations et la propriété Unix dans les fichiers appelés .pxovl.FILENAME
.
Le script bash ≥4 suivant est copié ~/mail/foo:bar
sur /media/usb99/mail/foo_bar
, et de même pour tous les fichiers sous ~/mail
. Les fichiers qui existent déjà dans l'arborescence de destination et qui ne sont pas plus anciens que la source sont ignorés.
#!/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
Ce script fonctionne sous zsh avec des modifications mineures: remplacez shopt -s dotglob globstar
par setopt dot_glob
et [[ $target -ot $source ]]
par [[ ! -e $target || $target -ot $source ]]
.
Voici un zsh à deux lignes (trois si vous comptez les chargements automatiques). C'est plus court, mais assez avancé et peu lisible.
autoload zargs zmv
zargs -- ~/mail/**/*(/e\''REPLY=/media/usb99/${${REPLY#$HOME/}//:/_}'\') -- mkdir -p --
zmv -C -Q -o -pu '~/mail/(**/)(*)(.)' '/media/usb99/mail/${1//:/_}${2//:/_}'
- La
zargs
ligne est équivalente à mkdir -p ~/mail/**/*(…)
, sauf qu'elle ne bombardera pas si la longueur cumulée des noms de répertoire est trop longue. Cette ligne crée les répertoires cibles selon les besoins.
~/mail/**/*(/)
s'étend à tous les répertoires sous ~/mail
(répertoires uniquement en raison de (/)
la fin).
(/e\''…'\')
sélectionne uniquement les répertoires et exécute ensuite le code dans «…» pour transformer chaque nom de fichier, qui est stocké dans la REPLY
variable.
${${REPLY#$HOME/}//:/_}
supprime le préfixe correspondant au répertoire source et se transforme :
en _
.
zmv -C
copie chaque fichier correspondant à son premier opérande (un modèle zsh) dans le nom de fichier obtenu en développant son deuxième opérande.
-o -pu
dit de passer -pu
à l' cp
utilitaire, afin de conserver les autorisations et de copier uniquement les fichiers mis à jour. (Nous pourrions dire à zsh d'effectuer la vérification de la mise à jour; ce serait un peu plus rapide mais encore plus cryptique.)
(.)
sélectionne uniquement les fichiers normaux. -Q
dit que cela doit être analysé comme un qualificatif glob et non comme .
avec des parenthèses autour d'elle indiquant une sous-expression.
$1
et $2
dans le texte de remplacement correspondent aux expressions entre parenthèses (**/)
et *
. ( **
perd sa signification spéciale comme zéro ou plusieurs niveaux de sous-répertoire s'il est entre parenthèses, sauf si les parenthèses contiennent exactement **/
.)
J'ai d'abord pensé à utiliser pax , qui est un outil d'archivage (ici destiné à être utilisé en mode pass-through) qui a une fonction de changement de nom de fichier (son -s
option). Cependant, les options -s
et -u
ne fonctionnent pas ensemble (la définition POSIX de pax dit littéralement que -u
doit vérifier un fichier du même nom dans l'arborescence de destination, plutôt que le nom de fichier transformé par -s
; l'implémentation de pax dans Ubuntu suit la spécification littéralement plutôt que utilement). Il est toujours possible de l'utiliser pour créer des liens durs renommés, puis de copier les liens durs (avec rsync -au
ou pax -rw -pp -u
) sur les autres supports, mais cela semble plus problématique que cela ne vaut.
cd ~/mail
mkdir -p /media/usb99/mail
pax -rw -l -pp -s '!:!_!g' . ../mail.colonless
rsync -au ../mail.colonless/ /media/usb99/mail/