obtener el último objeto modificado de la CLI de S3

80

Tengo un caso de uso en el que abro programáticamente una instancia EC2, copio un archivo ejecutable de S3, lo ejecuto y cierro la instancia (hecho en datos de usuario). Necesito obtener solo el último archivo agregado de S3. ¿Hay alguna forma de obtener el último archivo / objeto modificado de un depósito de S3 mediante la CLI?

deseoso
fuente
¿Puedes involucrar un lenguaje de programación en absoluto
Drew
CLI será la mejor opción ya que planeo tenerlo en los datos del usuario durante el lanzamiento de la instancia.
wishy
¿Programa en algún idioma con s3?
Drew
1
¿Existe una mejor solución para cubos con más de 2 millones de objetos?
lonewarrior556
1
Para muchos objetos, creo que una mejor solución sería crear un Event/Lambdaen el objeto que se activa ObjectCreation. buscar el último objeto entre 2M + objetos usando s3 cli o api es mucho más lento.
Vaulstein

Respuestas:

174

Puede enumerar todos los objetos en el depósito con aws s3 ls $BUCKET --recursive:

$ aws s3 ls $BUCKET --recursive
2015-05-05 15:36:17          4 an_object.txt
2015-06-08 14:14:44   16322599 some/other/object
2015-04-29 12:09:29      32768 yet-another-object.sh

Están ordenados alfabéticamente por clave, pero esa primera columna es la última hora de modificación. Un rápido sortreordenará por fecha:

$ aws s3 ls $BUCKET --recursive | sort
2015-04-29 12:09:29      32768 yet-another-object.sh
2015-05-05 15:36:17          4 an_object.txt
2015-06-08 14:14:44   16322599 some/other/object

tail -n 1selecciona la última fila y awk '{print $4}'extrae la cuarta columna (el nombre del objeto).

$ aws s3 ls $BUCKET --recursive | sort | tail -n 1 | awk '{print $4}'
some/other/object

Por último, pero no menos importante, suelte eso aws s3 cppara descargar el objeto:

$ KEY=`aws s3 ls $BUCKET --recursive | sort | tail -n 1 | awk '{print $4}'`
$ aws s3 cp s3://$BUCKET/$KEY ./latest-object
David Murray
fuente
2
Publicación brillante. Particularmente útil debido a las explicaciones de cada comando. Gracias.
Christian
4
S3 solo indexa objetos por clave. Si el depósito tiene suficientes objetos para que un "escaneo completo de la tabla" para encontrar el que está buscando no sea práctico, deberá crear un índice por separado. La opción más perezosa que se me ocurre es poner la clave del objeto escrito más recientemente en s3: // $ BUCKET / current después de haberlo escrito, y hacer que los lectores busquen allí cuál deben extraer.
David Murray
Solo una nota al margen, si desea lo mismo para una "carpeta" completa, awkdeberá seleccionar el segundo elemento (en lugar del cuarto) y --recursiveserá necesario, por ejemplo,KEY=`aws s3 ls $BUCKET --recursive | sort | tail -n 1 | awk '{print $2}'` ; aws s3 cp s3://$BUCKET/$KEY ./latest-object --recursive
David Arenburg
3
Esto no funcionará en depósitos con más de 1000 elementos, porque es lo máximo que se puede devolver docs.aws.amazon.com/cli/latest/reference/s3/ls.html
nico
esta línea no funcionará, aws s3 cp s3://$BUCKET/$KEY ./latest-objectel script anterior regresará"object"
Madeo
23

Después de un tiempo hay una pequeña actualización de cómo hacerlo un poco elegante:

aws s3api list-objects-v2 --bucket "my-awesome-bucket" --query 'sort_by(Contents, &LastModified)[-1].Key' --output=text

En lugar de una reversefunción adicional , podemos obtener la última entrada de la lista a través de[-1]

Respuesta anterior:

Este comando simplemente hace el trabajo sin dependencias externas:

aws s3api list-objects-v2 --bucket "my-awesome-bucket" --query 'reverse(sort_by(Contents, &LastModified))[:1].Key' --output=text
Roman Shishkin
fuente
3
Excelente. Si también necesita que el nombre del objeto coincida con una determinada cadena:--query 'reverse(sort_by(Contents[?contains(Key, `myKey`)], &LastModified))[:1].Key'
bfcapell
5
--query se ejecuta localmente, por lo que si tiene más de 1000 archivos en el depósito, no se garantiza que obtenga primero los últimos modificados.
Gismo Ranas
@GismoRanas Buen punto. La --filteropción regular se puede aplicar para reducir una lista
Roman Shishkin
11
aws s3api list-objects-v2 --bucket "bucket-name" |jq  -c ".[] | max_by(.LastModified)|.Key"
AlexLoo
fuente
Si nunca ha conocido a jq antes, es un procesador json stedolan.github.io/jq
andrew lorien
3
Creo que list-objects-v2tiene un límite en los elementos máximos, por lo que si su cubo tiene más objetos que eso, es posible que esto no obtenga una respuesta precisa
Gilad Peleg
docs.aws.amazon.com/cli/latest/reference/s3api/… establece (al momento de escribir este artículo) que el límite máximo por página es 1000. También tenga en cuenta que la salida se ha IsTruncatedestablecido en verdadero si hay más claves disponibles para devolver.
Ashutosh Jindal
2

A continuación se muestra el script bash, que descarga el último archivo de un S3 Bucket. En su lugar, utilicé el comando AWS S3 Synch , de modo que no descargaría el archivo de S3 si ya existía.

--exclude, excluye todos los archivos

: incluye, incluye todos los archivos que coinciden con el patrón

#!/usr/bin/env bash

    BUCKET="s3://my-s3-bucket-eu-west-1/list/"
    FILE_NAME=`aws s3 ls $BUCKET  | sort | tail -n 1 | awk '{print $4}'`
    TARGET_FILE_PATH=target/datdump/
    TARGET_FILE=${TARGET_FILE_PATH}localData.json.gz

    echo $FILE_NAME
    echo $TARGET_FILE

    aws s3 sync $BUCKET $TARGET_FILE_PATH --exclude "*" --include "*$FILE_NAME*"

    cp target/datdump/$FILE_NAME $TARGET_FILE

ps Gracias @David Murray

AjitChahal
fuente
1

Si se trata de un archivo recién cargado, puede utilizar Lambda para ejecutar un fragmento de código en el nuevo objeto S3.

Si realmente necesita obtener el más reciente, puede nombrar sus archivos con la fecha primero, ordenar por nombre y tomar el primer objeto.

Jonathan Turpie
fuente
2
Desafortunadamente, este no es un archivo recién subido. Necesitaré el último archivo cargado que podría haberse cargado en cualquier momento.
Wishy