bash - 在需要在单引号内包含反引号的命令中替换变量
问题描述
我试图编写一个简单的 bash 脚本来使用现有问题中建议的脚本自动删除 30 天以上的 EBS 快照删除早于一个月的 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))
我已经尝试了 , , , , 的所有组合[
,"
并且\
我/
能`
想到'
让它工作,但到目前为止还没有运气!
解决方案
解决此问题的一种简单方法是在需要文字的反引号之后结束单引号,将您的扩展置于双引号扩展中,然后为命令的其余部分切换回单引号上下文:
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'
中,有三个不同的子字符串,每个子字符串都以不同的方式引用,语法引号字符在引用样式之间转换:- 第一个字符 ,
'
开始一个单引号上下文;它是 shell 语法,而不是数据。 Snapshots[?StartTime>=`
是第一个子串;因为它在单引号内,所以不会以任何方式修改(并且反引号不会被视为特殊的 shell),因此aws
完全按原样成为命令参数向量中字符串的一部分。- 下一个字符 another
'
结束单引号上下文;它也是 shell 语法,而不是数据。 - 下一个字符 ,
"
是 shell 语法,它启动一个双引号上下文。这是因为在双引号上下文中,保证参数扩展不会进行字符串拆分或全局扩展。 $date
,在双引号上下文中,是扩展为包含子字符串的第二个段 - 替换为命名变量的值。这种扩展的结果,在双引号中,被视为没有应用进一步解析步骤的数据。- 接下来
"
是结束双引号上下文的语法。 - 接下来
'
是开始一个新的单引号上下文的语法。 `].SnapshotId
,被视为数据的第三个子字符串,在该单引号上下文中作为文字给出;由于该上下文,反引号文字aws
按原样传递。- 最后
'
是结束单引号上下文的语法。
- 第一个字符 ,
使用小写的变量名称
date
符合 POSIX 指南,该指南指定全大写名称用于对 shell 和 OS 提供的工具有意义的变量,而保留至少一个字符的名称供应用程序使用。请参阅http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html,记住 shell 和环境变量共享一个命名空间。- 替换
snapshots_to_delete=( $(...) )
是出于BashPitfalls #50中描述的原因:- Using
IFS=$'\n' read -r -d '' -a snapshots_to_delete
导致 stdin 在换行符处从流中拆分为数组元素,该流预计以单个 NUL 字节结尾。如果该 NUL 字节不存在,read
将以非零状态退出(指示错误)。 - 如果命令成功,则放在命令
&& printf '\0'
末尾aws
会导致发出 NUL 字节。通过这种方式,我们确保将成功或失败的信息传播回命令;这也可以移植到旧版本的 bash,而不是支持替代或命令。aws
aws
read
readarray
mapfile
$( ... )
作为命令替换,比反引号更受欢迎,因为反引号会更改反斜杠和其中其他反引号的含义,除非包含的内容更改其引用。见http://wiki.bash-hackers.org/syntax/expansion/cmdsubst#a_closer_look_at_the_two_forms
- Using
- 使用
read -r -a < <(...)
而不是... | read -r -a
出于BashFAQ #24中所述的原因。有问题的语法也称为“进程替换”,记录在http://wiki.bash-hackers.org/syntax/expansion/proc_subst
推荐阅读
- algorithm - 如何在字符串级别压缩文本?
- java - AbstractTableModel 的问题,表格不显示
- php - 在php中按键递归排序多维数组的函数
- xquery - 如何使用 s9api XQuery 转换在 xml 转换中获取元素节点
- sap - 从 SAP PI 向 SAP 系统发送消息时出现 HTTP404
- python - 从二叉树在 pygraphviz 中创建 DOT 边
- spring-boot - 如何强制spring不压缩日志文件,而是在日志文件末尾附加日期
- powershell - 如何通过 Powershell 编辑组织单位 (OU) GPO
- php - 上传 RecyclerView 到 PHP 服务器 Android
- solr - DSE Solr 中的多个 OR 范围