如何在Bash中将here-string放入变量中:
在Bash中使用
read
,将
-d
分隔符设置为null:
IFS= read -r -d '' cmd <<EOC
...blah blah...
EOC
请确保在read
前使用如下的IFS=
,否则会去除任何开头和结尾的空格。请确保使用-r
,否则一些反斜杠会被理解为转义反斜杠。
有人可能会认为只需使用普通赋值更简单:
cmd='
...blah blah...
'
但有时你有很多引用,以至于使用这个会变得更加简单和好看。
微妙的说明。使用此选项,由于未在EOF之前读取空字节分隔符,
read
将返回一个失败的返回代码(1)。虽然大多数情况下这是没问题的,但如果你正在使用
set -e
(但
你真的不应该使用set -e
),那么这可能会成为一个问题。如果你想要确定,可以添加:
IFS= read -r -d '' cmd <<EOC || true
...blah blah...
EOC
现在,认真地谈谈你的问题。
以下是一条非常重要的提示:不要把代码放进字符串中!它会出错!。相反,使用函数或(虽然不好,但不会出错)数组。以下是如何使用数组:
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"
)
(注意我费心打出的引号,带着爱)。
然后你可以安全地运行它(安全地运行是指如果你在参数中有glob字符、引号或空格也没关系),如下所示:
"${mycommand[@]}"
注意正确使用引号。如果想要打印命令,请使用以下代码:
printf '%s\n' "${mycommand[*]}"
很遗憾,这里无法保留换行符。但实际上,这应该不是什么问题。如果真的需要,你应该通过某种格式化程序(或许它不存在,所以你需要自己编写)来传递此命令。但要按照正确顺序进行:你需要定义一个
命令,执行它(并且可选地对其进行格式化,以供用户显示),而不是反过来,先有一个对用户友好的字符串,然后必须解析(危险地)以将其转换为代码。
CMD
变量中(顺便说一下,你不需要这样做,请参考http://mywiki.wooledge.org/BashFAQ/001),那么直接使用带引号的字符串即可,如`CMD="docker run ...."`。 - Etan Reisnerset -x
很可能比手动 echo 命令具有更好的verbose
模式 (虽然更加冗长,并且在某些情况下阅读起来有些奇怪)。 - Etan Reisner