我有一些像这样的代码:
CMD=$(cat <<EOC
docker run
-p $MY_IP:$LOCAL_PORT:$LOCAL_PORT -p $MY_IP:$PEER_PORT:$PEER_PORT
-v $CERT_DIR:/cert
$ETCD_IMAGE
--name $MACHINE.$DOMAIN
--peer-cert-file=/cert/server-cert.pem
--peer-key-file=/cert/server-key.pem --peer-ca-file=/cert/ca.pem
--peer-addr=$MY_IP:$PEER_PORT
--peers=$OIPPC
EOC
)
有没有办法让这里的doc直接将结果分配给bash中的变量而不需要介入进程(cat)?这段代码有效,只是感觉太多了。
答案 0 :(得分:2)
如何将here-string放入Bash中的变量:
在Bash中使用read
并将-d
分隔符设置为null:
IFS= read -r -d '' cmd <<EOC
...blah blah...
EOC
确保在IFS=
前面确实使用了read
,否则将修剪任何前导和尾随空格。确保使用-r
,否则一些反斜杠将被理解为转义反斜杠。
有些人认为使用普通作业更简单:
cmd='
...blah blah...
'
但有时你会有很多引用,以至于使用它会变得更简单和更好。
微妙的注释。这样,read
返回失败返回码(1),因为在EOF之前未读取空字节定界符。虽然大部分时间都没问题,但如果您使用的是set -e
(you really shouldn't use set -e
anyway),则可能会出现问题。如果您想确定,请添加:
IFS= read -r -d '' cmd <<EOC || true
...blah blah...
EOC
下面是一个严肃的说明,你真的应该考虑:不要把代码放到字符串中! it's broken!。相反,使用一个函数或(仍然坏,但没有破坏)数组。以下是使用数组的方法:
mycommand=(
docker run
-p "$MY_IP:$LOCAL_PORT:$LOCAL_PORT"
-p "$MY_IP:$PEER_PORT:$PEER_PORT"
-v "$CERT_DIR":/cert
"$ETCD_IMAGE"
--name "$MACHINE.$DOMAIN"
--peer-cert-file=/cert/server-cert.pem
--peer-key-file=/cert/server-key.pem
--peer-ca-file=/cert/ca.pem
--peer-addr="$MY_IP:$PEER_PORT"
--peers="$OIPPC"
)
(观察我花时间打字的引号,带着爱)。 然后你可以安全地运行它(安全地说,如果你的参数中有浮点字符或引号或空格,它就没问题了):
"${mycommand[@]}"
(再次观察健康的报价)。如果要打印命令,请使用:
printf '%s\n' "${mycommand[*]}"
不幸的是,这里不会保留换行符。但实际上,这应该不是问题。如果真的需要,你应该通过某种格式化程序传递这个命令(好吧,很可能它不存在所以你必须自己编写代码)。但是把事情按正确的顺序排列:你想定义一个命令,执行它(并且,可选择格式化它,供用户显示),而不是反过来,有一个很好的字符串然后用户的眼睛必须解析(危险地)转换成代码。