Automatizar transferências com Azure CLI e verificar os bytes
Use az storage blob upload para enviar um arquivo local ao Azure Blob Storage, depois faça o
download e compare os bytes. O script abaixo faz isso para um arquivo ou um diretório de arquivos.
Ele recusa nomes de blobs existentes e só informa que um lote foi concluído quando todos os arquivos
selecionados passam na comparação.
Instalar e configurar
Este guia usa Bash no Linux e o contêiner da Azure CLI da Microsoft, testado com a Azure CLI 2.91.0. Você precisa de uma instalação funcional do Docker, permissão para executar contêineres e um diretório de trabalho com permissão de escrita. Mantenha os arquivos de origem inalterados durante a transferência. As transferências e o armazenamento geram cobranças do Azure; comece com arquivos pequenos e sem dados sensíveis.
O contêiner fornece Bash e Python, por isso o script não precisa de uma instalação da Azure CLI no host. Siga o guia de contêineres da Microsoft para obter os detalhes de instalação da imagem. Baixe a imagem testada e verifique a CLI dentro dela:
docker pull mcr.microsoft.com/azure-cli:2.91.0-azurelinux3.0 &&
docker run --rm mcr.microsoft.com/azure-cli:2.91.0-azurelinux3.0 az version
Escolher o destino e a autorização
Use uma conta de armazenamento e um contêiner de blobs privado já existentes nos quais seu administrador tenha autorizado você a gravar. Para novas contas, use o tipo de uso geral v2, conforme descrito na visão geral das contas da Microsoft. Privado, neste contexto, significa que o acesso anônimo aos blobs está desabilitado. Sua máquina ainda precisa de uma rota de rede funcional até o endpoint de Blob da conta.
Este exemplo usa autenticação Shared Key. Seu administrador precisa permiti-la explicitamente e
fornecer o nome e a chave da conta pelo seu gerenciador de segredos, como as variáveis de ambiente
exportadas AZURE_STORAGE_ACCOUNT e AZURE_STORAGE_KEY. A chave concede acesso amplo à
conta: mantenha-a fora de scripts, do histórico do shell e dos logs. Execute isto somente onde essa
autorização for apropriada.
A Microsoft recomenda a autorização do Microsoft Entra
quando disponível. Com --auth-mode login, a identidade precisa de uma função de acesso a
dados de blobs; uma função de gerenciamento de armazenamento, por si só, é insuficiente. Este script
exige deliberadamente uma chave fornecida; ele não faz login, consulta chaves de conta, cria recursos
nem atribui funções. Uma conta que desabilita Shared Key precisa de outra configuração de
autenticação.
Transferir arquivos usando Azure CLI
Salve o conteúdo a seguir como transfer.sh no seu diretório de trabalho. Seus quatro
argumentos são o arquivo ou diretório de origem, o nome do contêiner existente, o novo prefixo dos
nomes de blobs e o novo diretório de download. Use caminhos relativos dentro desse diretório de
trabalho, como ./input.bin e ./downloads, para que o contêiner possa
acessá-los. O diretório pai do diretório de download já deve existir.
Os caminhos de origem e os nomes de arquivos devem ser UTF-8 válidos, sem retornos de carro nem
quebras de linha. Há suporte a espaços, sinais de porcentagem literais, #,
?, hífens iniciais e nomes de arquivos Unicode. O prefixo usa letras ASCII
minúsculas, dígitos, barras, sublinhados e hífens; comece com uma letra ou um dígito e evite segmentos
vazios, . ou ... Um prefixo como
transfers/run-001 cria nomes de blobs aninhados sem precisar criar diretórios remotos.
#!/usr/bin/env bash
set -uo pipefail
for tool in az python3 mkdir sleep; do
command -v "$tool" >/dev/null || { printf 'Missing tool: %s\n' "$tool" >&2; exit 1; }
done
: "${AZURE_STORAGE_ACCOUNT:?Set AZURE_STORAGE_ACCOUNT}"
: "${AZURE_STORAGE_KEY:?Set AZURE_STORAGE_KEY}"
unset AZURE_STORAGE_CONNECTION_STRING AZURE_STORAGE_SAS_TOKEN AZURE_STORAGE_SERVICE_ENDPOINT
if [ "$#" -ne 4 ]; then
printf 'Usage: bash transfer.sh SOURCE CONTAINER PREFIX DOWNLOAD_DIR\n' >&2
exit 2
fi
source_path=$1
container=$2
prefix=$3
download_dir=$4
case "$source_path" in /*) ;; *) source_path="./$source_path" ;; esac
case "$download_dir" in /*) ;; *) download_dir="./$download_dir" ;; esac
if ! python3 - "$source_path" "$prefix" "$download_dir" <<'PY'
import os
import re
import sys
try:
source, prefix, destination = sys.argv[1:]
paths = [source, destination]
if os.path.isdir(source):
with os.scandir(source) as entries:
paths.extend(entry.path for entry in entries
if entry.is_file(follow_symlinks=False))
for path in paths:
os.fsencode(path).decode('utf-8')
if '\n' in path or '\r' in path:
raise ValueError()
if not re.fullmatch(r'[a-z0-9][a-z0-9/_-]*', prefix):
raise ValueError()
if any(part in ('', '.', '..') for part in prefix.split('/')):
raise ValueError()
except (OSError, UnicodeError, ValueError):
print('Check source access, UTF-8 paths, and the blob prefix.', file=sys.stderr)
sys.exit(1)
PY
then
exit 1
fi
if [ -L "$source_path" ] || { [ ! -f "$source_path" ] && [ ! -d "$source_path" ]; }; then
printf 'Source must be a regular file or directory, not a symbolic link.\n' >&2
exit 1
fi
mkdir -- "$download_dir" || exit 1
shopt -s nullglob dotglob
files=("$source_path")
if [ -d "$source_path" ]; then files=("$source_path"/*); fi
failed=0
verified=0
max_retries=3
for file in "${files[@]}"; do
[ -f "$file" ] && [ ! -L "$file" ] || continue
filename=${file##*/}
blob_name="$prefix/$filename"
uploaded=0
for ((attempt=1; attempt<=max_retries; attempt++)); do
if az storage blob upload --account-name "$AZURE_STORAGE_ACCOUNT" \
--container-name "$container" --name "$blob_name" --file "$file" \
--type block --auth-mode key --overwrite false \
--only-show-errors --output none >/dev/null 2>&1; then
uploaded=1
break
fi
if [ "$attempt" -lt "$max_retries" ]; then sleep 5; fi
done
if [ "$uploaded" -eq 0 ]; then
printf 'Upload refused or failed: %s\n' "$filename" >&2
failed=$((failed + 1))
continue
fi
downloaded_file="$download_dir/$filename"
if ! az storage blob download --account-name "$AZURE_STORAGE_ACCOUNT" \
--container-name "$container" --name "$blob_name" --file "$downloaded_file" \
--auth-mode key --overwrite false --only-show-errors --output none >/dev/null 2>&1; then
printf 'Download failed: %s\n' "$filename" >&2
failed=$((failed + 1))
continue
fi
if ! python3 - "$file" "$downloaded_file" <<'PY'
import filecmp
import sys
sys.exit(0 if filecmp.cmp(sys.argv[1], sys.argv[2], shallow=False) else 1)
PY
then
printf 'Byte comparison failed: %s\n' "$filename" >&2
failed=$((failed + 1))
continue
fi
printf 'Verified: %s\n' "$filename"
verified=$((verified + 1))
done
printf 'Verified %s file(s); failed %s.\n' "$verified" "$failed"
if [ "$failed" -ne 0 ]; then exit 1; fi
printf 'Transfer complete\n'
Fazer upload de arquivos
Coloque um arquivo chamado input.bin ao lado do script salvo. Com as duas variáveis
de credenciais já exportadas, substitua your-container pelo nome do seu contêiner
existente e escolha um prefixo ainda não usado. Execute:
docker run --rm --user "$(id -u):$(id -g)" \
--env HOME=/tmp --env AZURE_CONFIG_DIR=/tmp/azure \
--env AZURE_CORE_COLLECT_TELEMETRY=no \
--env AZURE_STORAGE_ACCOUNT --env AZURE_STORAGE_KEY \
--mount "type=bind,source=$PWD,target=/work" --workdir /work \
mcr.microsoft.com/azure-cli:2.91.0-azurelinux3.0 \
bash transfer.sh ./input.bin your-container transfers/run-001 ./downloads
O contêiner encerra a execução em seguida; o blob enviado permanece no Azure e o download permanece
no seu diretório de trabalho. A opção --user mantém os arquivos baixados sob a
propriedade do seu usuário do Linux.
Fazer download de arquivos
O comando az storage blob download do script recupera exatamente o nome de blob usado no upload, e
o Python compara o download completo com a origem local. Uma execução bem-sucedida para um único
arquivo imprime Verified: input.bin, depois Verified 1 file(s); failed 0. e
Transfer complete. Arquivos vazios também são válidos. Um upload bem-sucedido seguido de
falha no download ou na comparação retorna um código de saída diferente de zero e mantém o blob
remoto no lugar para inspeção.
Ambas as transferências usam explicitamente --overwrite false; consulte a
referência de upload
e a referência de download.
O script também recusa um diretório de download existente antes de contatar o Azure. Para repetir uma
execução, escolha um novo prefixo e um novo diretório de download. Reutilizar um nome de blob com um
novo diretório de download resulta em falha, em vez de substituir o blob anterior. Essa recusa é
intencional; o script não implementa substituição no local nem reversão das alterações.
Automatizar transferências de arquivos em lote com Azure CLI
Coloque seus arquivos em ./input, depois use o mesmo script com esse diretório
como primeiro argumento:
docker run --rm --user "$(id -u):$(id -g)" \
--env HOME=/tmp --env AZURE_CONFIG_DIR=/tmp/azure \
--env AZURE_CORE_COLLECT_TELEMETRY=no \
--env AZURE_STORAGE_ACCOUNT --env AZURE_STORAGE_KEY \
--mount "type=bind,source=$PWD,target=/work" --workdir /work \
mcr.microsoft.com/azure-cli:2.91.0-azurelinux3.0 \
bash transfer.sh ./input your-container transfers/batch-001 ./batch-downloads
Isso seleciona os arquivos regulares diretamente dentro de ./input, incluindo
arquivos ocultos. Subdiretórios e links simbólicos são ignorados; não há busca recursiva. O nome de
cada arquivo selecionado se torna o último segmento do nome do blob e do nome do download local. Um
diretório vazio conclui a execução com zero arquivos verificados, então confira a contagem impressa
se você esperava uma quantidade maior de arquivos.
As transferências são executadas sequencialmente. Cada upload tem no máximo três invocações da CLI,
com um intervalo de cinco segundos após uma falha; as próprias tentativas da CLI junto ao serviço
são adicionais. Cada download tem uma invocação da CLI. A contagem final inclui todos os uploads,
downloads e comparações que falharam, mesmo que os arquivos seguintes tenham sucesso. Um lote
parcialmente bem-sucedido encerra a execução com um código diferente de zero e mantém os blobs e
downloads bem-sucedidos. Ele nunca imprime Transfer complete para esse resultado.
Solucionar problemas comuns
Se uma variável de credencial estiver ausente, o script para antes de criar o diretório de download. Em caso de recusa de upload, confira com o administrador a conta selecionada, o contêiner, a autorização da chave e a rota de rede. O script informa o nome do arquivo afetado e suprime os diagnósticos brutos da CLI para manter credenciais e URLs assinadas fora da saída.
Uma falha de upload também pode significar que o nome do blob já existe. Três tentativas recusadas não tornam a substituição segura. Uma resposta perdida pode deixar um blob já gravado mesmo quando o comando falha; inspecione esse nome exato antes de tentar novamente. Use um prefixo ainda não usado para outra cópia, em vez de alterar a política de sobrescrita para contornar uma recusa.
Se o download ou a comparação falhar, inspecione separadamente o blob mantido e o download local. Mantenha a origem intacta. O script não exclui downloads parciais, não desfaz uploads bem-sucedidos nem altera as configurações de retenção da conta. Combine qualquer limpeza com o proprietário do recurso usando os nomes exatos dos blobs daquela execução.
Próximos passos
Para requisições HTTP diretas em vez de automação por CLI, consulte como exportar arquivos para o Azure com cURL. Esse é um fluxo de trabalho REST separado; sua autenticação e seu programa de upload não são necessários aqui.
