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/