A abordagem mais direta é aproveitar a camada do sistema de arquivos para transformar os nomes dos arquivos. Desde o Ubuntu 12.04, existe 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 exigir acesso root:
mkdir ~/mnt
/sbin/mount.posixovl -S /media/sdb1 ~/mnt
rsync -au ~/mail ~/mnt/
Os caracteres nos nomes de arquivo que o VFAT não aceita são codificados como %(XX)
onde XX
estão os dígitos hexadecimais. A partir do POSIXovl 1.2.20120215, observe que um nome de arquivo como %(3A)
é codificado como ele mesmo e será decodificado como :
, para que haja risco de colisão se você tiver nomes de arquivo contendo substrings do formulário %(XX)
.
Cuidado que o POSIXovl não lida com nomes de arquivos muito longos. Se o nome codificado não couber em 255 caracteres, o arquivo não poderá ser armazenado.
O POSIXovl armazena permissões e propriedade unix em arquivos chamados .pxovl.FILENAME
.
O script bash ≥4 a seguir copia ~/mail/foo:bar
para /media/usb99/mail/foo_bar
e da mesma forma para todos os arquivos em ~/mail
. Os 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 no 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 zsh de duas linhas (três se você contar os carregamentos automáticos). É mais curto, mas bastante avançado e não muito 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
zargs
linha é equivalente a mkdir -p ~/mail/**/*(…)
, exceto que ela não será bombardeada se o comprimento acumulado dos nomes de diretório for muito longo. Essa linha cria os diretórios de destino conforme necessário.
~/mail/**/*(/)
expande para todos os diretórios em ~/mail
(diretórios somente devido ao (/)
final).
(/e\''…'\')
seleciona apenas diretórios e executa ainda mais o código em '…' para transformar cada nome de arquivo, que é armazenado na REPLY
variável.
${${REPLY#$HOME/}//:/_}
remove o prefixo correspondente ao diretório de origem e muda :
para _
.
zmv -C
copia cada arquivo que corresponde ao seu primeiro operando (um padrão zsh) para o nome do arquivo obtido expandindo seu segundo operando.
-o -pu
diz para passar -pu
para o cp
utilitário, a fim de preservar permissões e copiar apenas arquivos atualizados. (Poderíamos dizer ao zsh para executar a verificação da 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 de glob e não como um .
entre parênteses indicando uma subexpressão.
$1
e $2
no texto de substituição correspondem às expressões entre parênteses (**/)
e *
. ( **
perde seu significado especial como zero ou mais níveis de subdiretório, se estiver entre parênteses, a menos que os parênteses contenham exatamente **/
.)
Inicialmente, pensei em usar o pax , que é uma ferramenta de arquivamento (aqui destinada a ser usada no modo de passagem) que possui um recurso de renomeação de arquivos (sua -s
opção). No entanto, os -s
e -u
opções não funcionam juntos (a definição POSIX de pax literalmente diz que -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 pax no Ubuntu segue a especificação literalmente ao invés de de forma útil). Ainda é possível utilizá-lo para criar links físicos renomeados e depois copiá-los (com rsync -au
ou pax -rw -pp -u
) para outras mídias, mas parece haver mais problemas 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/