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/..
priya
fonte

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

número 5
fonte
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)
Steffen Opel
fonte
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

Ryan
fonte
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

MichaelZ
fonte
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;
};
abgui
fonte
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.

Hajime
fonte
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 }
velaskec
fonte
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/*" 
Einarc
fonte
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);
Shriganesh Shintre
fonte
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
Imdad
fonte