给出以下语法:
x=(-a 2);echo "${x[@]}";x=(-e 2 -e); echo "${x[@]}"
输出:
-a 2
2 -e
期望的输出
-a 2
-e 2 -e
为什么会这样?我该如何解决?
答案 0 :(得分:11)
printf "%s\n" "${x[*]}"
echo
有3种选择:
$ help echo
[…]
Options:
-n do not append a newline
-e enable interpretation of the following backslash escapes
-E explicitly suppress interpretation of backslash escapes
所以如果你跑:
$ echo -n
$ echo -n -e
$ echo -n -e -E
你一无所获。即使你把每个选项都放在引号中,它看起来仍然与bash相同:
$ echo "-n"
$ echo "-n" "-e"
最后一个命令使用两个参数运行echo
:-n
和-e
。现在将其与:
$ echo "-n -e"
-n -e
我们所做的是使用一个参数:echo
运行-n -e
。由于bash无法识别(组合)选项-n -e
,它最终会像我们想要的那样回应终端的单个参数。
在第二种情况下,数组x
以元素-e
开头。在bash扩展数组${x[@]}
之后,您实际上正在运行:
$ echo "-e" "2" "-e"
2 -e
由于第一个参数是-e
,它被解释为一个选项(而不是回显到终端),正如我们已经看到的那样。
现在将其与其他样式的数组扩展${x[*]}
进行对比,它有效地执行以下操作:
$ echo "-e 2 -e"
-e 2 -e
bash看到单个参数-e 2 -e
- 因为它不能识别它作为一个选项 - 它将该参数回显给终端。
请注意,${x[*]}
样式展开通常不安全。请看以下示例:
$ x=(-e)
$ echo "${x[*]}"
即使我们期望-e
得到回应,也不会打印任何内容。如果你一直在关注,你已经知道为什么会这样。
解决方案是转义echo
命令的任何参数。不幸的是,与其他提供某种说法的命令不同,“嘿!以下参数不应被解释为选项“(通常是--
参数),bash不为echo
提供此类转义机制。
幸运的是,printf
命令提供了echo
提供的功能的超集。因此,我们得出了解决方案:
printf "%s\n" "${x[*]}"
答案 1 :(得分:2)
-e
被解释为echo的选项(启用转义序列'
通常,你会做echo -- "-e"
之类的事情,它应该只打印-e
,但echo很乐意表现不同,只需将-- -e
打印成整个字符串。
echo不解释 - 意味着选项的结束。
问题的解决方案也可以在手册页中找到:
由于shell别名和内置
echo
命令,使用了朴实的 交互式地或在脚本中echo
可以为您提供不同的功能 比这里描述的那样。通过env
调用它(即env echo ...
) 避免来自外壳的干扰。
所以这样的事情应该有效:
x=(-a 2);echo "${x[@]}";x=(-e 2 -e); env echo "${x[@]}"
答案 2 :(得分:2)
@MichaelKropat's answer gives sufficient explanation
作为echo
(和printf
)的替代方案,可以使用cat
和bash here-string:
$ x=(-a 2);cat <<< "${x[@]}";x=(-e 2 -e); cat <<< "${x[@]}"
-a 2
-e 2 -e
$