Como excluir arquivos recursivamente de um balde S3


87

Eu tenho a seguinte estrutura de pastas no S3. Existe uma maneira de remover recursivamente todos os arquivos em uma determinada pasta (digamos foo/bar1 or foo or foo/bar2/1...)

foo/bar1/1/..
foo/bar1/2/..
foo/bar1/3/..

foo/bar2/1/..
foo/bar2/2/..
foo/bar2/3/..

Respostas:


164

Com as ferramentas de linha de comando aws-cli python mais recentes , para excluir recursivamente todos os arquivos em uma pasta em um intervalo é apenas:

aws s3 rm --recursive s3://your_bucket_name/foo/

Ou exclua tudo sob o balde:

aws s3 rm --recursive s3://your_bucket_name

Se o que você deseja é realmente excluir o intervalo, há um atalho de uma etapa:

aws s3 rb --force s3://your_bucket_name

que removerá o conteúdo desse intervalo recursivamente e, em seguida, excluirá o intervalo.

Observação: o s3://prefixo do protocolo é necessário para que esses comandos funcionem


2
esta deve ser a resposta. É um (novo) padrão, ferramenta poderosa, projetada para coisas como esta pergunta
— Don Cheadle

Isso está excluindo os arquivos, mas também excluindo o balde depois de excluir os arquivos. Eu perdi alguma coisa?
— Naveen

1
@Naveen como eu disse acima, rmapenas excluirá arquivos, mas rb --forceexcluirá os arquivos e o balde.
— número 5

5
usando --recursiveexclui a pasta também.
— Ryantuck

1
@Moseleyi eu acredito que você não pode realmente ter uma pasta vazia em um balde s3
— ryantuck

58

Isso costumava exigir uma chamada de API dedicada por chave (arquivo), mas foi muito simplificado devido à introdução do Amazon S3 - Multi-Object Delete em dezembro de 2011:

O novo Multi-Object Delete do Amazon S3 oferece a capacidade de excluir até 1000 objetos de um bucket do S3 com uma única solicitação.

Veja minha resposta à pergunta relacionada delete from S3 using api php using wildcard para obter mais informações sobre este e respectivos exemplos em PHP (o SDK da AWS para PHP suporta isso desde a versão 1.4.8 ).

A maioria das bibliotecas cliente da AWS, entretanto, introduziu suporte dedicado para esta funcionalidade de uma forma ou de outra, por exemplo:

Pitão

Você pode conseguir isso com a excelente interface boto Python para AWS mais ou menos da seguinte maneira (não testado, do topo da minha cabeça):

import boto
s3 = boto.connect_s3()
bucket = s3.get_bucket("bucketname")
bucketListResultSet = bucket.list(prefix="foo/bar")
result = bucket.delete_keys([key.name for key in bucketListResultSet])

Rubi

Isso está disponível desde a versão 1.24 do SDK da AWS para Ruby e as notas de versão também fornecem um exemplo:

bucket = AWS::S3.new.buckets['mybucket']

# delete a list of objects by keys, objects are deleted in batches of 1k per
# request.  Accepts strings, AWS::S3::S3Object, AWS::S3::ObectVersion and 
# hashes with :key and :version_id
bucket.objects.delete('key1', 'key2', 'key3', ...)

# delete all of the objects in a bucket (optionally with a common prefix as shown)
bucket.objects.with_prefix('2009/').delete_all

# conditional delete, loads and deletes objects in batches of 1k, only
# deleting those that return true from the block
bucket.objects.delete_if{|object| object.key =~ /\.pdf$/ }

# empty the bucket and then delete the bucket, objects are deleted in batches of 1k
bucket.delete!

Ou:

AWS::S3::Bucket.delete('your_bucket', :force => true)

deve usar a nova aws cliresposta como @ number5 abaixo docs.aws.amazon.com/cli/latest/reference/s3/rm.html
— Don Cheadle

43

Você também pode considerar o uso do Amazon S3 Lifecycle para criar uma expiração para arquivos com o prefixo foo/bar1.

Abra o console do navegador S3 e clique em um balde. Em seguida, clique em Propriedades e depois em Ciclo de vida.

Crie uma regra de expiração para todos os arquivos com o prefixo foo/bar1e defina a data como 1 dia desde a criação do arquivo.

Salve e todos os arquivos correspondentes desaparecerão em 24 horas.

Só não se esqueça de remover a regra depois de terminar!

Sem chamadas de API, sem bibliotecas, aplicativos ou scripts de terceiros.

Acabei de deletar vários milhões de arquivos dessa forma.

Uma captura de tela mostrando a janela da Regra do Ciclo de Vida (observe nesta foto que o Prefixo foi deixado em branco, afetando todas as chaves no intervalo):

insira a descrição da imagem aqui


4
Ótima ideia para usar o Lifecycle em vez de algum comando de exclusão.
— xis

Exatamente, deixe o S3 fazer isso por você.
— Ryan

Você também pode aplicar isso a todo o intervalo, permitindo que você exclua o intervalo.
— Indolente de

8

Com o s3cmdpacote instalado em uma máquina Linux, você pode fazer isso

s3cmd rm s3://foo/bar --recursive


1
De acordo com a ajuda, é uma exclusão de objeto único s3cmd del s3://BUCKET/OBJECTou exclusão de todo o intervalo s3cmd rb s3://BUCKET. Não há s3cmd rm, pelo menos de acordo com s3cmd --help.
— Paul McMurdie

s3cmd rmestá na ajuda a partir de 2019 (como um apelido para del), esta é uma excelente resposta. As awsferramentas cli funcionam apenas com um /prefixo de terminação, mas não com uma pasta e um prefixo de nome de arquivo parcial, enquanto s3cmd funciona em ambos os casos. Esta resposta precisa de muito mais votos positivos, tive que rolar muito para encontrar a solução certa.
— David Parks de

8

No caso, se você deseja remover todos os objetos com o prefixo "foo /" usando Java AWS SDK 2.0

import java.util.ArrayList;
import java.util.Iterator;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.*;

//...

ListObjectsRequest listObjectsRequest = ListObjectsRequest.builder()
    .bucket(bucketName)
    .prefix("foo/")
    .build()
;
ListObjectsResponse objectsResponse = s3Client.listObjects(listObjectsRequest);

while (true) {
    ArrayList<ObjectIdentifier> objects = new ArrayList<>();

    for (Iterator<?> iterator = objectsResponse.contents().iterator(); iterator.hasNext(); ) {
        S3Object s3Object = (S3Object)iterator.next();
        objects.add(
            ObjectIdentifier.builder()
                .key(s3Object.key())
                .build()
        );
    }

    s3Client.deleteObjects(
        DeleteObjectsRequest.builder()
            .bucket(bucketName)
            .delete(
                Delete.builder()
                    .objects(objects)
                    .build()
            )
            .build()
    );

    if (objectsResponse.isTruncated()) {
        objectsResponse = s3Client.listObjects(listObjectsRequest);
        continue;
    }

    break;
};

1
Não consigo encontrar uma demonstração mais reveladora do que as pessoas não gostam em Java do que esta resposta ...
— Jivan

3

No caso de usar AWS-SKD para ruby ​​V2.

s3.list_objects(bucket: bucket_name, prefix: "foo/").contents.each do |obj|
  next if obj.key == "foo/" 
  resp = s3.delete_object({
    bucket: bucket_name,
    key: obj.key,
  })
end

atenção, todos os "foo / *" no balde serão excluídos.


2

Acabei de remover todos os arquivos do meu intervalo usando o PowerShell:

Get-S3Object -BucketName YOUR_BUCKET | % { Remove-S3Object -BucketName YOUR_BUCKET -Key $_.Key -Force:$true }

Obrigado por postar esta resposta, eu estava tentando fazer exatamente isso e coloquei -Key "% _. Key" que não funciona.
— Scott Gartner


1

A resposta votada está faltando uma etapa.

Por ajuda do aws s3:

Atualmente, não há suporte para o uso de curingas de estilo UNIX em argumentos de caminho de comando. No entanto, a maioria dos comandos tem --exclude "<value>"e --include "<value>" parâmetros que podem alcançar o resultado desejado ......... Quando há vários filtros, a regra é que os filtros que aparecem posteriormente no comando têm precedência sobre os filtros que aparecem anteriormente no comando. Por exemplo, se os parâmetros de filtro passados ​​para o comando forem --exclude "*" --include "*.txt"Todos os arquivos serão excluídos do comando, exceto para arquivos que terminam com .txt

aws s3 rm --recursive s3://bucket/ --exclude="*" --include="/folder_path/*" 

0

A melhor maneira é usar a regra de ciclo de vida para excluir todo o conteúdo do balde. Programaticamente, você pode usar o seguinte código (PHP) para PUT regra de ciclo de vida.

$expiration = array('Date' => date('U', strtotime('GMT midnight')));
$result = $s3->putBucketLifecycle(array(
            'Bucket' => 'bucket-name',
            'Rules' => array(
                array(
                    'Expiration' => $expiration,
                    'ID' => 'rule-name',
                    'Prefix' => '',
                    'Status' => 'Enabled',
                ),
            ),
        ));

No caso acima, todos os objetos serão excluídos. Data de início - "Hoje à meia-noite GMT".

Você também pode especificar os dias da seguinte forma. Mas com o Dias, ele aguardará pelo menos 24 horas (no mínimo 1 dia) para começar a excluir o conteúdo do balde.

$expiration = array('Days' => 1);

0

Eu precisava fazer o seguinte ...

def delete_bucket
  s3 = init_amazon_s3
  s3.buckets['BUCKET-NAME'].objects.each do |obj|
    obj.delete
  end
end

def init_amazon_s3
  config = YAML.load_file("#{Rails.root}/config/s3.yml")
  AWS.config(:access_key_id => config['access_key_id'],:secret_access_key => config['secret_access_key'])
  s3 = AWS::S3.new
end
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.