Подстановка переменной в команде, которая должна содержать обратную черту в одинарных кавычках - PullRequest
0 голосов
/ 08 октября 2018

Я пытался написать простой bash-скрипт для автоматического удаления снимков EBS старше 30 дней, используя скрипт, предложенный в существующем вопросе Удалить снимки старше AWS EC2 старше месяца

Однако,Я не могу запустить его правильно или выбрать дату как переменную:

Исходный код выглядит следующим образом:

snapshots_to_delete=($(aws ec2 describe-snapshots --owner-ids xxxxxxxxxxxx --query 'Snapshots[?StartTime>=`2017-02-15`].SnapshotId' --output text))

Я хочу, чтобы он запускался примерно так:

DATE=`date --date="3 month ago" +%Y-%m-%d`

snapshots_to_delete=($(aws ec2 describe-snapshots --owner-ids xxxxxxxxxxxx --query 'Snapshots[?StartTime>=$DATE].SnapshotId' --output text))

Я пробовал каждую комбинацию [, ", \, /, ` и ' Я могу придумать, как это работает, но пока не повезло!

1 Ответ

0 голосов
/ 08 октября 2018

Простой способ исправить это - завершить одинарные кавычки после обратного кавычка, который должен быть буквальным, поместить ваше расширение в расширение двойных кавычек, а затем переключиться обратно на одинарные кавычкиконтекст для остальной части команды:

date=$(date --date="3 month ago" +%Y-%m-%d)

IFS=$'\n' read -r -d '' -a snapshots_to_delete < <(
  aws ec2 describe-snapshots \
    --owner-ids xxxxxxxxxxxx \
    --query 'Snapshots[?StartTime>=`'"$date"'`].SnapshotId' && printf '\0'
)
declare -p snapshots_to_delete >&2 # print the resulting value

Зачем писать это так?

  • В 'Snapshots[?StartTime>=`'"$date"'`].SnapshotId' есть три различных подстроки, каждая из которых заключена в разныеКстати, с помощью синтаксических символов кавычек, переходящих между стилями кавычек:

    1. Первый символ, ', запускает контекст в одинарных кавычках;это синтаксис оболочки, а не данные.
    2. Snapshots[?StartTime>=` - первая подстрока;поскольку он находится внутри одинарных кавычек , он никак не изменяется (и обратный удар не рассматривается как особый для оболочки) и, таким образом, становится частью строки в векторе аргументов команды awsв точности как есть.
    3. Следующий символ, еще один ', завершает контекст, заключенный в одинарные кавычки;это также синтаксис оболочки, а не данные.
    4. Следующий символ, ", это синтаксис оболочки, который запускает контекст в двойных кавычках.Это связано с тем, что в контексте двойных кавычек расширения параметров гарантированно не подвергаются разделению строк или расширению глобуса.
    5. $date, в контексте двойных кавычек - это второй сегмент, который расширяется и содержитподстрока - заменяется значением именованной переменной.Результат этого расширения, заключенный в двойные кавычки, обрабатывается как данные без дополнительных шагов анализа.
    6. Следующий " - это синтаксис, который завершает контекст в двойных кавычках.
    7. next ' - это синтаксис, который начинает новый контекст в одинарных кавычках.
    8. `].SnapshotId, третья подстрока, обработанная как данные, задается как литерал внутри этого контекста в одинарных кавычках;из-за этого контекста литерал обратного ключа передается в aws в точности как есть.
    9. Последний ' - это синтаксис, который завершает контекст в одинарных кавычках.
  • Использование имени переменной в нижнем регистре для date соответствует рекомендациям POSIX, определяющим, что имена всех заглавных букв должны использоваться для переменных, значимых для оболочки и предоставляемых ОС инструментов, тогда как имена, содержащие не менее одного символа, являютсязарезервировано для использования приложения.См. http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html,, учитывая, что переменные оболочки и среды совместно используют пространство имен.

  • Замена snapshots_to_delete=( $(...) ) по причинам, описанным в BashPitfalls # 50 :
    • Использование IFS=$'\n' read -r -d '' -a snapshots_to_delete приводит к разделению stdin на элементы массива на новых строках потока, который, как ожидается, заканчивается одним байтом NUL.Если этот NUL-байт отсутствует, read завершится с ненулевым состоянием (что указывает на ошибку).
    • Помещение && printf '\0' в конце команды aws приводит к выдаче NUL-байта если и если команда aws выполнена успешно .Таким образом, мы убедились, что информация о том, успешно или неудачно aws передана обратно в команду read;это также переносимо на более старые версии bash, чем поддержка альтернативных команд readarray или mapfile.
    • $( ... ) предпочтительнее обратных кавычек в качестве подстановки команд, поскольку обратные косые черты изменяют значение обратных косых черт и других обратных кавычек вих, если это содержание не меняет свое цитирование.См. http://wiki.bash -hackers.org / синтаксис / расширение / cmdsubst # a_closer_look_at_the_two_forms
  • Использование read -r -a < <(...) вместо ... | read -r -a по причинам, описанным в BashFAQ # 24 .Синтаксис, о котором идет речь, также известен как «подстановка процесса», задокументированная по адресу http://wiki.bash -hackers.org / syntax / extension / proc_subst
...