为什么bash吞咽-e在阵列的前面

时间:2014-01-15 23:54:17

标签: bash

给出以下语法:

x=(-a 2);echo "${x[@]}";x=(-e 2 -e); echo "${x[@]}"

输出:

-a 2
2 -e

期望的输出

-a 2
-e 2 -e

为什么会这样?我该如何解决?

3 个答案:

答案 0 :(得分:11)

TL;博士

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 here-string

$ x=(-a 2);cat <<< "${x[@]}";x=(-e 2 -e); cat <<< "${x[@]}"
-a 2
-e 2 -e
$