在需要在单引号内包含反引号的命令中替换变量

时间:2018-10-08 16:44:49

标签: bash aws-cli

我试图编写一个简单的bash脚本,以使用现有问题Delete older than month AWS EC2 snapshots中建议的脚本自动删除30天以上的EBS快照

但是,我无法使其正常运行或将日期作为变量:

原始代码如下:

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 :(得分:3)

解决此问题的一种简单方法是,在需要用文字表示的反引号后面的后面加上单引号,将扩展名放在双引号中,然后切换回单引号。其余命令的引用上下文:

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. 第一个字符'以单引号引起来;它是shell语法,而不是数据。
    2. Snapshots[?StartTime>=`是第一个子字符串;因为它在单引号中,所以它没有进行任何修改(反引号对于shell来说不是特殊的),因此成为aws中字符串的一部分命令的参数向量完全按原样。
    3. 下一个字符,另一个',结束该单引号上下文;它也是shell语法,而不是数据。
    4. 下一个字符"是shell语法,用于启动双引号上下文。这是因为在双引号中,保证参数扩展不会进行字符串拆分或glob扩展。
    5. 在双引号内的
    6. $date是扩展为包含子字符串的第二段-用命名变量的值替换。扩展后的结果用双引号括起来,被视为没有应用进一步解析步骤的数据。
    7. 下一个"是结束双引号上下文的语法。
    8. 下一个'是开始新的单引号上下文的语法。
    9. `].SnapshotId,第三个被视为数据的子字符串,在该单引号上下文内以文字形式给出;由于这种情况,反引号文字会原样传递给aws
    10. 最后一个'是结束单引号上下文的语法。
  • date使用小写的变量名符合POSIX准则,该准则指定全大写名称用于对Shell和OS提供的工具有意义的变量,而名称至少具有保留一个字符供应用程序使用。请参见http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html,请记住shell和环境变量共享一个名称空间。

  • 替换snapshots_to_delete=( $(...) )是出于BashPitfalls #50中所述的原因:
    • 使用IFS=$'\n' read -r -d '' -a snapshots_to_delete会使stdin从预期以单个NUL字节结尾的流的换行符处拆分为数组元素。如果该NUL字节不存在,则read将以非零状态退出(表示错误)。
    • 如果&& printf '\0'命令成功,则将aws放在aws命令的末尾会导致发出NUL字节。这样,我们确保将aws成功或失败的信息传播回read命令;除了支持替代readarraymapfile命令之外,这对于较旧版本的bash也可移植。
    • 在命令行中,
    • $( ... )优于反引号,因为反引号会更改反斜杠和其中的其他反引号的含义,除非所包含的内容更改了其引号。参见http://wiki.bash-hackers.org/syntax/expansion/cmdsubst#a_closer_look_at_the_two_forms
  • 使用read -r -a < <(...)代替... | read -r -a是出于BashFAQ #24中所述的原因。有问题的语法也称为“进程替换”,记录在http://wiki.bash-hackers.org/syntax/expansion/proc_subst