我正在尝试在容器内运行一个带有重定向的命令,该重定向应该在容器内工作,该命令应该存储在一个变量中。这是我在容器中运行的命令
consul kv export > /consul/data/backup.json
这是我从docker主机上尝试的命令
docker exec f0a57e0592e5 consul kv export > /consul/data/backup.json
这不起作用,因为重定向发生在主机上,而不是在容器内
为了工作,我不得不使用shell在容器内执行重定向
docker exec f0a57e0592e5 sh -c 'consul kv export > /consul/data/backup.json'
在这里工作之前,我需要的是能够将所有这些命令作为变量传递
command="docker exec f0a57e0592e5 sh -c 'consul kv export > /consul/data/backup.json'"
但当执行$command
时,我收到kv: 1: Syntax error: Unterminated quoted string
为什么
引用bash手动
在将拆分为标记后,在命令行上执行扩展。执行的扩展有七种:
- 支架展开
- 波浪形展开
- 参数与变量展开
- 命令替换
- 算术展开
- 分词
- 文件名扩展
所以键入这个
command="docker exec f0a57e0592e5 sh -c 'consul kv export > /consul/data/backup.json'"
做你想做的事。双引号可防止随地吐痰。所以它只是command=something
,没有其他令牌。到目前为止还不错。
现在,当你输入
$command
$command
扩展为
docker exec f0a57e0592e5 sh -c 'consul kv export > /consul/data/backup.json'
这条生产线是用膨胀链的剩余部分处理的。但不是重新启动整个评估链。
因此,在变量替换之后是命令替换($(...)
或`...`
(。这些都没有。
然后对CCD_ 11。也没有。
然后是单词纵切。因此,我们吐出单词,即docker
exec
f0a57e0592e5
sh
-c
'consul
kv
export
>
/consul/data/backup.json'
这里的引号不被解释为防止拆分。现在找引号已经太迟了。这发生在";代币";第一阶段。这是在引用之前完成的。所以这些引号在这里只是字符。
所以CCD_ 22是用所述自变量来执行的。包括一个'consul
自变量。这不是你所期望的。
实验
如果你有
command="printf (%s)"
然后
$command 1 2 3
给出(1)(2)(3)
而
$command "1 2 3"
给出(1 2 3)
我想,不出所料。因为"
在第一阶段就存在,令牌分裂,并被解释为防止后来的单词分裂。
但试试这个变体
command="printf (%s) 1 2"
$command 3 4 5
还是没什么奇怪的→(1)(2)(3)(4)(5)
command="printf (%s) '1 2'"
$command '3 4 5'
→('1)(2')(3 4 5)
这可能很奇怪。但这很正常。看看会发生什么:
$command '3 4 5'
标记$command
(变量引用(3 4 5
(字符串——通过标记化发现其中的空格是文字空间,因为被引号包围。我用表示(
- 没有大括号,没有可展开的波浪号
- 我们替换变量,所以现在要评估的行是
printf (%s) '1 2' 3 4 5
- 无
$(...)
无$((...)
可扩展 - 分为单词:
printf
(%s)
'1
2'
3 4 5
。请注意,在此阶段的'
只是字符。对他们来说,影响标记化已经太晚了,就像3 4 5
周围的人所做的那样。因此,1
和2
之间的空间确实分割了单词,与3
、4
和5
之间的空间相反,由于'
的存在,这些空间通过标记化转换为文字空间 - exec
- →
('1)(2')(3 4 5)
正是我们得到的。当我们了解我们的命令到底发生了什么时,即使是最奇怪的结果也是完全可以预测的。
解决方案
你可以使用臭名昭著的evalcommand="eval docker exec f0a57e0592e5 sh -c 'consul kv export > /consul/data/backup.json'"
这迫使扩展链从头开始,包括标记化。
但是,和往常一样,必须小心处理eval,尤其是在其中包含用户输入部分的情况下。这里的情况似乎并非如此。因为如果链中的任何东西扩展到; rm -fr /
,你就知道会发生什么。。。
或者您可以尝试创建一个脚本/path/bin/myscript
#!/bin/bash
docker exec f0a57e0592e5 sh -c 'consul kv export > /consul/data/backup.json'
然后有command=/path/bin/myscript
所以$command
只是执行该脚本(这是受控的eval
。因为启动脚本是强制评估其内容(。
或者,根据上下文,与函数或别名相同。