Crie, verifique e restaure um backup do projeto com zip
Para que um backup ZIP reflita o estado atual do seu projeto, crie um arquivo ZIP novo a cada
execução. Executar zip -r sobre um arquivo ZIP existente adiciona ou atualiza entradas, mas pode
manter arquivos que você excluiu da origem. O manual do Info-ZIP
documenta esse comportamento. A seguir, um script Bash cria um arquivo ZIP novo, verifica esse
arquivo e só então substitui o backup anterior.
Este passo a passo tem como alvo o Linux com Bash, Info-ZIP Zip 3.0, UnZip 6.0, GNU coreutils,
findutils e diffutils. Consulte zip -v e unzip -v para ver as versões do Info-ZIP. O script usa o
mv -T do GNU, então precisa de adaptação para o macOS. O Make é opcional.
Pare builds e outros processos que gravam no projeto antes de arquivar. O resultado representa
um diretório que permanece inalterado durante a execução; o zip não tira um snapshot do sistema
de arquivos. Use arquivos comuns, diretórios e links simbólicos, sem caracteres de controle nos
nomes.
Prepare um projeto pequeno
Execute este bloco no Bash. Ele cria um projeto descartável e se recusa a reutilizar um diretório
zip-demo existente. Os parênteses mantêm seu shell no diretório original.
(
set -euo pipefail
mkdir zip-demo
cd zip-demo
mkdir -p project_directory/src project_directory/node_modules project_directory/dist
printf 'version one\n' > project_directory/src/app.txt
printf 'project notes\n' > 'project_directory/read me.txt'
printf 'dependency\n' > project_directory/node_modules/omit.txt
printf 'generated\n' > project_directory/dist/omit.txt
)
Crie um arquivo ZIP novo a cada execução
Salve este script como zip-demo/backup.sh. Ele arquiva project_directory em relação ao seu diretório de
trabalho. Mantenha o script, o arquivo ZIP temporário e o arquivo ZIP final ao lado do projeto,
fora da árvore de código-fonte.
#!/usr/bin/env bash
set -euo pipefail
umask 077
unset ZIPOPT UNZIP UNZIPOPT
source_dir=project_directory
backup_date=$(date +%Y-%m-%d)
archive_name="project_backup_$backup_date.zip"
if [[ ! -d "$source_dir" || -L "$source_dir" ]]; then
printf 'Source must be a real directory: %s\n' "$source_dir" >&2
exit 1
fi
if [[ -L "$archive_name" || ( -e "$archive_name" && ! -f "$archive_name" ) ]]; then
printf 'Destination must be a regular file or absent: %s\n' "$archive_name" >&2
exit 1
fi
find "$source_dir" -type d -print > /dev/null
work_dir=$(mktemp -d './.zip-backup.XXXXXXXX')
trap 'rm -rf -- "$work_dir"' EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
zip -q -6 -r -MM -y "$work_dir/archive.zip" "$source_dir" \
-x '*/.git' '*/.git/*' \
'*/node_modules' '*/node_modules/*' \
'*/dist' '*/dist/*' \
'*.tmp' '*.tmp/*' '*.temp' '*.temp/*' \
'*/.DS_Store' '*/.DS_Store/*'
unzip -tq "$work_dir/archive.zip"
mv -fT -- "$work_dir/archive.zip" "$archive_name"
printf 'Backup created: %s\n' "$archive_name"
Execute-o a partir do diretório onde você criou zip-demo:
(cd zip-demo && bash backup.sh)
Em caso de sucesso, a última linha informa o nome project_backup_YYYY-MM-DD.zip usando a data local da máquina.
Uma execução bem-sucedida no mesmo dia substitui esse arquivo sem pedir confirmação. Arquivos
adicionados aparecem, arquivos alterados são relidos e arquivos excluídos desaparecem, mesmo quando
uma alteração preserva o tamanho e a data de modificação de um arquivo. Com entradas inalteradas, o
conteúdo restaurado permanece o mesmo; não há garantia de bytes idênticos no arquivo ZIP.
O destino só é substituído depois que a compressão e a verificação são concluídas com sucesso. Uma origem ausente, um arquivo ilegível ou uma verificação com falha retorna um status diferente de zero sem a mensagem de sucesso e mantém o backup anterior no lugar. Um destino que seja um diretório ou um link simbólico é rejeitado. Execute um backup por vez em um diretório que você controla.
O find inicial verifica se toda a árvore de origem pode ser percorrida, incluindo os diretórios
excluídos. Isso importa porque o zip pode ignorar silenciosamente um diretório ilegível mesmo com
-MM. As opções têm funções específicas: -r percorre o diretório, -MM torna fatais os
arquivos de entrada ausentes ou ilegíveis e -y armazena os links simbólicos em vez de seus destinos.
Colocar os padrões de exclusão entre aspas deixa a correspondência a cargo do zip. Essas são
opções do Info-ZIP.
O script limpa as opções herdadas do ZIP/UnZip para que as configurações padrão do shell não possam
alterar silenciosamente seu comportamento.
O mv -fT do GNU substitui o arquivo de destino,
tratando-o como um caminho de arquivo e não como um diretório para onde mover.
Escolha o que excluir
O exemplo omite .git, node_modules e dist em qualquer profundidade, nomes terminados em .tmp ou
.temp, além de .DS_Store. A correspondência também abrange diretórios com esses nomes e seu
conteúdo. Por exemplo, */node_modules/* corresponde tanto a project_directory/node_modules/omit.txt quanto às dependências
de um pacote aninhado.
Essas exclusões são adequadas para a entrega de um código-fonte cujas dependências e saída de build podem ser recriadas. Remova exclusões se esses arquivos fizerem parte do que você precisa restaurar. Fora isso, os dotfiles são incluídos, então inspecione o arquivo ZIP antes de compartilhá-lo: esta lista não é um detector de segredos. Se você alterá-la, altere também as exclusões da comparação abaixo.
Execute o mesmo script pelo Make
Opcionalmente, salve isto como zip-demo/Makefile, com uma tabulação antes de bash. Execute make -C zip-demo archive
a partir do diretório pai. O alvo phony é executado todas as vezes, e o Make informa uma falha do
script como uma falha do alvo.
.PHONY: archive
archive:
bash backup.sh
Restaure e compare os arquivos
Execute este bloco a partir do diretório pai de zip-demo no mesmo dia do backup. Para um backup mais
antigo, substitua a expressão de data pelo nome real do arquivo. Restaure apenas um arquivo ZIP em
que você confia.
(
set -euo pipefail
cd zip-demo
unset UNZIP UNZIPOPT ZIPINFO ZIPINFOOPT
archive_name="project_backup_$(date +%Y-%m-%d).zip"
unzip -tq "$archive_name"
unzip -Z1 "$archive_name"
mkdir restored
unzip -q "$archive_name" -d restored
diff -r --no-dereference \
-x .git -x node_modules -x dist -x '*.tmp' -x '*.temp' -x .DS_Store \
project_directory restored/project_directory
)
A listagem de membros deve conter src/app.txt e read me.txt dentro de project_directory/,
sem os arquivos de dependências e os arquivos gerados. A árvore restaurada mantém esse diretório de
nível superior. O diff não produz saída e termina com status zero quando o conteúdo dos arquivos
incluídos, a estrutura de diretórios e os destinos dos links simbólicos coincidem. Ele não compara
proprietário, permissões nem timestamps.
O mkdir restored falha deliberadamente se esse destino já existir, antes que a extração mexa nele. Para
repetir uma restauração, escolha um novo nome de diretório tanto no comando de extração quanto no de
comparação. Se a extração falhar no meio do caminho, mantenha esse diretório parcial separado e tente
novamente em um diretório novo.
O manual do UnZip explica
que -t descompacta as entradas e verifica seus CRCs armazenados. Isso detecta dados danificados,
mas não prova que você incluiu os arquivos certos. A restauração e a comparação separadas verificam
essa parte, desde que a origem tenha permanecido inalterada desde o backup.
Escolha um nível de compressão
Altere -6 no script quando quiser comparar níveis:
| Opção | Finalidade |
|---|---|
-0 | Armazenar arquivos sem compressão |
-1 | Priorizar a velocidade de compressão |
-6 | Usar o nível de compressão padrão do Info-ZIP |
-9 | Dedicar mais tempo para tentar gerar um resultado menor |
As opções de nível de compressão controlam o esforço de compressão. Não há uma economia percentual fixa, e um nível mais alto não necessariamente produz um arquivo ZIP significativamente menor. Compare o tempo decorrido e o tamanho do arquivo ZIP no seu projeto real e depois restaure cada candidato. Lembre-se de que este script substitui a saída do mesmo dia, então salve cada candidato separadamente se quiser mantê-lo.
Criptografe separadamente quando necessário
Este arquivo ZIP não é criptografado. O zip -e do Info-ZIP usa a criptografia ZIP tradicional, que é
fraca; o FAQ do Info-ZIP alerta sobre suas limitações.
Para material sensível, escolha um fluxo de trabalho de criptografia separado, como o
age, que oferece suporte a chaves de destinatário e frases secretas. Confirme
que o destinatário consegue descriptografar e restaurar o arquivo antes de confiar nesse fluxo de
trabalho. A criptografia também mantém o ZIP original não criptografado no disco, a menos que você
gerencie essa cópia separadamente.
Lide com falhas e limites
Se uma execução falhar, inspecione o diagnóstico e o status de saída; um ZIP mais antigo no destino não é evidência de que a tentativa de hoje funcionou. Mantenha espaço livre suficiente para o arquivo ZIP anterior e o novo ao mesmo tempo. Em uma falha comum, o trap de saída remove o diretório temporário; um encerramento forçado ou uma queda de energia pode deixá-lo para trás.
Este exemplo verifica o conteúdo e os caminhos dos arquivos de um projeto no Linux. Ele não estabelece um formato completo de backup de sistema para ACLs, atributos estendidos, arquivos especiais ou relações de hard links. Arquivos ZIP grandes podem exigir suporte a Zip64 no extrator do destinatário. Mantenha os backups bem-sucedidos mais antigos de acordo com suas próprias necessidades de retenção e teste a restauração com as ferramentas que realmente vão consumi-los.
