A abordagem mais direta é aproveitar a camada do sistema de arquivos para transformar os nomes dos arquivos. Desde o Ubuntu 12.04, há um sistema de arquivos FUSE que transforma nomes de arquivos em nomes que o VFAT do Windows suporta: fuse-posixovl
.
sudo mount.posixovl /media/sdb1
chown guillaume /media/sdb1
rsync -au ~/mail /media/sbd1/
Ou para evitar a necessidade de acesso root:
mkdir ~/mnt
/sbin/mount.posixovl -S /media/sdb1 ~/mnt
rsync -au ~/mail ~/mnt/
Caracteres em nomes de arquivos que o VFAT não aceita são codificados como %(XX) , em que XX são dígitos hexadecimais. A partir do POSIXovl 1.2.20120215, lembre-se de que um nome de arquivo como %(3A) é codificado como ele mesmo e será decodificado como : , portanto, há risco de colisão se você tiver nomes de arquivos contendo substrings no formato %(XX) .
Cuidado com o fato de o POSIXovl não lidar com nomes de arquivos muito longos. Se o nome codificado não couber em 255 caracteres, o arquivo não pode ser armazenado.
O POSIXovl armazena permissões de unix e propriedade em arquivos chamados .pxovl.FILENAME .
O seguinte bash ≥4 cópias de script ~/mail/foo:bar to /media/usb99/mail/foo_bar e, da mesma forma, para todos os arquivos em ~/mail . Arquivos que já existem na árvore de destino e que não são mais antigos que a origem são ignorados.
#!/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
Este script funciona em zsh com pequenas modificações: substitua shopt -s dotglob globstar por setopt dot_glob e [[ $target -ot $source ]] por [[ ! -e $target || $target -ot $source ]] .
Aqui está um two-liner zsh (três se você contar os autoloads). É mais curto, mas bastante avançado e pouco legível.
autoload zargs zmv
zargs -- ~/mail/**/*(/e\''REPLY=/media/usb99/${${REPLY#$HOME/}//:/_}'\') -- mkdir -p --
zmv -C -Q -o -pu '~/mail/(**/)(*)(.)' '/media/usb99/mail/${1//:/_}${2//:/_}'
- A linha
zargs é equivalente a mkdir -p ~/mail/**/*(…) , exceto pelo fato de não bombardear se o comprimento acumulado dos nomes dos diretórios for muito longo. Essa linha cria os diretórios de destino conforme necessário.
-
~/mail/**/*(/) se expande para todos os diretórios em ~/mail (diretórios apenas devido ao (/) no final).
-
(/e\''…'\') seleciona apenas diretórios e executa o código dentro de '…' para transformar cada nome de arquivo, que é armazenado na variável REPLY .
-
${${REPLY#$HOME/}//:/_} remove o prefixo correspondente ao diretório de origem e altera : para _ .
-
zmv -C copia cada arquivo correspondente a seu primeiro operando (um padrão zsh) para o nome do arquivo obtido pela expansão de seu segundo operando.
-
-o -pu diz para passar -pu para o utilitário cp , para preservar as permissões e copiar apenas os arquivos atualizados. (Poderíamos dizer ao zsh para executar a verificação de atualização; seria um pouco mais rápido, mas ainda mais enigmático.)
-
(.) seleciona apenas arquivos regulares. -Q diz que isso deve ser analisado como um qualificador glob e não como . com parênteses ao redor, indicando uma subexpressão.
-
e no texto de substituição correspondem às expressões com parênteses (**/) e * . ( ** perde seu significado especial como zero ou mais níveis de subdiretórios se estiver entre parênteses, a menos que os parênteses contenham exatamente **/ .)
Inicialmente, pensei em usar pax , que é uma ferramenta de arquivamento
(aqui destinado a ser usado no modo de passagem) que possui um recurso de renomeação de arquivo (sua opção -s ). No entanto, as opções -s e -u não funcionam juntas (a definição POSIX de pax -u deve verificar um arquivo com o mesmo nome na árvore de destino, em vez do nome do arquivo transformado por -s ; a implementação da pax no Ubuntu segue a especificação literalmente, e não útil). Ainda é possível fazer uso dele para criar links físicos renomeados e, em seguida, copiar os links físicos (com rsync -au ou pax -rw -pp -u ) para as outras mídias, mas isso parece mais problemático do que vale a pena.
cd ~/mail
mkdir -p /media/usb99/mail
pax -rw -l -pp -s '!:!_!g' . ../mail.colonless
rsync -au ../mail.colonless/ /media/usb99/mail/