получить последний измененный объект из S3 CLI

80

У меня есть вариант использования, когда я программно вызываю экземпляр EC2, копирую исполняемый файл из S3, запускаю его и закрываю экземпляр (выполняется в пользовательских данных). Мне нужно получить только последний добавленный файл из S3. Есть ли способ получить последний измененный файл / объект из корзины S3 с помощью интерфейса командной строки?

слабый
источник
Можете ли вы вообще задействовать язык программирования?
Дрю
CLI будет лучшим вариантом, поскольку я планирую добавить его в пользовательские данные во время запуска экземпляра.
Wishy
Вы программируете на каких языках с s3?
Дрю
1
Есть ли лучшее решение для ведер с 2M + объектами?
lonewarrior556
1
Я думаю, что для многих объектов лучшим решением было бы создать Event/Lambdaобъект, который запускается ObjectCreation. выборка последнего объекта среди 2M + объектов с использованием s3 cli или api работает медленнее.
Vaulstein

Ответы:

174

Вы можете перечислить все объекты в ведре с помощью 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

Они отсортированы в алфавитном порядке по ключу, но в первом столбце указано время последнего изменения. Быстро sortотсортирует их по дате:

$ 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 1выбирает последнюю строку и awk '{print $4}'извлекает четвертый столбец (имя объекта).

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

И последнее, но не менее важное: вставьте это, aws s3 cpчтобы загрузить объект:

$ KEY=`aws s3 ls $BUCKET --recursive | sort | tail -n 1 | awk '{print $4}'`
$ aws s3 cp s3://$BUCKET/$KEY ./latest-object
Дэвид Мюррей
источник
2
Блестящий пост. Особенно полезно из-за объяснения каждой команды. Благодарю.
Кристиан
4
S3 индексирует объекты только по ключу. Если в корзине достаточно объектов, поэтому «полное сканирование таблицы» для поиска нужной вам нецелесообразно, вам необходимо создать отдельный собственный индекс. Самый ленивый вариант, который я могу придумать, - это поместить ключ последнего записанного объекта в s3: // $ BUCKET / current после того, как вы его написали, и попросить читателей посмотреть там, чтобы найти, какой из них им следует извлечь.
Дэвид Мюррей
Замечание: если вы хотите сделать то же самое для всей «папки», вам awkнужно будет выбрать второй элемент (вместо 4-го), и --recursiveон понадобится, например,KEY=`aws s3 ls $BUCKET --recursive | sort | tail -n 1 | awk '{print $2}'` ; aws s3 cp s3://$BUCKET/$KEY ./latest-object --recursive
Дэвид Аренбург
3
Это не будет работать на ведра с более чем 1000 пунктов, потому что это самое большее , что может быть возвращен docs.aws.amazon.com/cli/latest/reference/s3/ls.html
Nico
эта строка не будет работать, aws s3 cp s3://$BUCKET/$KEY ./latest-objectпредыдущий сценарий вернется"object"
Мадео
23

Через некоторое время есть небольшое обновление, как сделать это немного элегантнее:

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

Вместо дополнительной reverseфункции мы можем получить последнюю запись из списка через[-1]

Старый ответ:

Эта команда просто выполняет работу без каких-либо внешних зависимостей:

aws s3api list-objects-v2 --bucket "my-awesome-bucket" --query 'reverse(sort_by(Contents, &LastModified))[:1].Key' --output=text
Роман Шишкин
источник
3
Превосходно. Если вам также нужно, чтобы имя объекта соответствовало определенной строке:--query 'reverse(sort_by(Contents[?contains(Key, `myKey`)], &LastModified))[:1].Key'
bfcapell
5
--query выполняется локально, поэтому, если у вас более 1000 файлов в корзине, вы не гарантируете, что сначала получите последние измененные.
Gismo Ranas
@GismoRanas Хорошее замечание. --filterМожно применить штатную опцию для уменьшения списка
Роман Шишкин
11
aws s3api list-objects-v2 --bucket "bucket-name" |jq  -c ".[] | max_by(.LastModified)|.Key"
AlexLoo
источник
Если вы никогда раньше не встречали jq, то это json-процессор stedolan.github.io/jq
Эндрю Лориен
3
Я думаю, что list-objects-v2есть ограничение на максимальное количество предметов, поэтому, если в вашем ведре больше предметов, чем это - это может не дать точного ответа
Гилад Пелег
В docs.aws.amazon.com/cli/latest/reference/s3api/… указано (на момент написания), что максимальный предел на страницу составляет 1000. Также обратите внимание, что для вывода IsTruncatedустановлено значение true, если доступно больше ключей для возврата.
Ашутош Джиндал
2

Ниже приведен сценарий bash, который загружает последний файл из S3 Bucket. Я использовал AWS S3 SynchВместо этого команду , чтобы она не загружала файл с S3, если он уже существует.

--exclude, исключает все файлы

--include, включает все файлы, соответствующие шаблону

#!/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 Спасибо @ Дэвид Мюррей

АджитЧахал
источник
1

Если это только что загруженный файл, вы можете использовать Lambda для выполнения фрагмента кода на новом объекте S3.

Если вам действительно нужно получить самый последний объект, вы можете сначала назвать файлы с датой, отсортировать по имени и взять первый объект.

Джонатан Терпи
источник
2
К сожалению, это не только что загруженный файл. Мне понадобится последний загруженный файл, который мог быть загружен в любое время.
Wishy