Usando o rsync para excluir padrões selecionados, corresponde a todos os arquivos

1

Eu quero usar rsync para remover certos arquivos (para Apagar eficientemente um grande diretório contendo milhares de arquivos ), neste caso dado a um script de shell como padrões na linha de comando.

Até agora, isso é o que eu tenho no meu script de shell rsync_del.sh

#!/bin/bash

TARGET_DIR=${1}
shift
PATTERNS="${@}"
for patt in ${PATTERNS} ; do
    # Both do the same
    #INCLUDE_PATTERNS="${INCLUDE_PATTERNS}"' --include='\'"${patt}"\'
    INCLUDE_PATTERNS="${INCLUDE_PATTERNS} --include=\"${pattern}\""
done

EMPTYDIR=$(mktemp -d)
echo "Created empty dir ${EMPTYDIR}"
comm="rsync -a --progress --delete ${INCLUDE_PATTERNS} ${EMPTYDIR}/ ${TARGET_DIR}"
echo ${comm}
eval ${comm}

Exemplos de padrões que eu gostaria de usar são *[1-9].txt , *000??9.txt . O problema é que, ao executar

rsync_del.sh trg_dir '*[1-9].txt'

a linha de comando gerada é

rsync -a --progress --delete --include='*[1-9].txt' /tmp/tmp.51R9hPgkfG/ trg_dir/

(o que parece ok para mim), mas é compatível, por exemplo, com arquivos como input.dat (e eu não quero isso).

Qual é a maneira correta de implementar / usar isso? Eu suspeito que é uma questão de escapar adequadamente dos padrões, mas eu não poderia fazer isso funcionar.

Nota: Eu preciso definir o comando a ser executado em uma variável, para echo it antes da execução.

    
por sancho.s 27.09.2018 / 08:26

2 respostas

1

Esqueci-me de que deveria fechar a lista de padrões, excluindo qualquer coisa não incluída explicitamente. Eu usei

comm="rsync -a --progress --delete ${INCLUDE_PATTERNS} --exclude=\"*\" ${EMPTYDIR}/ ${TARGET_DIR}"
    
por 27.09.2018 / 08:29
1

Não está olhando muito de perto o uso real de rsync aqui e, em vez disso, concentrando-se na criação da linha de comando rsync .

#!/bin/bash

target=$1
shift

empty=$( mktemp -d )

trap 'rmdir "$empty"' EXIT

for pattern do
   incl+=( --include="$pattern" )
done

rsync --archive --progress --delete "${incl[@]}" --exclude='*' "$empty"/ "$target"

Usando uma matriz (a matriz incl acima), você armazena os argumentos para rsync separadamente e não como uma string. A expansão de "${incl[@]}" será os elementos citados individualmente da matriz. Citando os argumentos torna-se trivial e não há necessidade de chamar eval . Note também que todas as expansões de parâmetros precisam ser duplamente citadas.

O problema com o seu código é que você usa a maioria das expansões de parâmetro sem aspas. Isso faz com que o shell execute a divisão de palavras e geração de nome de arquivo (globbing) nas variáveis. Isso, por sua vez, significa que você não pode usar padrões contendo espaços ou padrões de globalização de shell que podem se expandir para nomes de arquivos existentes.

Para /bin/sh , a sintaxe se torna ainda menos detalhada:

#!/bin/sh

target=$1
shift

empty=$( mktemp -d )

trap 'rmdir "$empty"' EXIT

for pattern do
   set -- "$@" --include="$pattern"
   shift
done

rsync --archive --progress --delete "$@" --exclude='*' "$empty"/ "$target"
    
por 27.09.2018 / 08:39