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}"
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.
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"
Tags bash rsync shell-script quoting