Bash: 为什么 echo 命令会添加额外空格?

14

我得到:

$ echo -e "D"{a,b,c}".jpg\n"
Da.jpg
 Db.jpg
 Dc.jpg

注意:输出的第二行和第三行在 Db 和 Dc 前面有额外的空格。

这些空格是为什么?

谢谢, 丹

编辑:由于我的实际目标中有空格(我本应该最初写出来):

echo -e "Name"{,.}" "{-,}"extra"{,so}" 5v5 "{one,two,No\ four}{,!,\!\!}"\n"

这里的大多数解决方案(包括for循环、xargs和tr)都对我没有用。Printf也无法使用,因为我想要实现多重花括号展开的笛卡尔积。

我将mletterle的\b、Dennis Williamson的额外空格和Jim Dennis的少引号方法结合起来,得到了以下解决方案:

echo -e "" \\bName{,.}\ {-,}extra{,so}\ 5v5\ {one,two,No\ four}{,\!,\!\!}\\n
感谢所有回答我的人!我从你们的回复中学到了很多!
Dan

2
echo 在这里无法做其他事情,它从 bash 获取空格。 - Alok Singhal
1
解决方法是使用以下命令:echo -e D{a,b,c}.jpg\n | tr -d " "(使用带有-d选项的翻译工具)。 (顺便说一句:您不需要那么多引号,只需一个额外的\就足够了)。 - Jim Dennis
7个回答

14

使用更具可移植性的printf函数

$ printf "D%s.jpg\n" {a,b,c}
Da.jpg
Db.jpg
Dc.jpg

建议使用POSIXy方式,避免使用echo及其所有陷阱。 - Jens

13
因为这就是花括号扩展的作用。从man bash中的Brace expansion标题下可知:

“要进行花括号扩展的模式采用一个可选的前缀,后跟由逗号分隔的一系列字符串,后面是一个可选的后缀。前缀添加到花括号内包含的每个字符串之前,然后将后缀附加到每个生成的字符串上,从左向右进行扩展。例如,a{d,c,b}e扩展为‘ade ace abe’。”

因此,在您的示例中,“D”是前缀,“.jpg\n”是后缀。因此,在进行花括号扩展后,您会得到:

echo -e Da.jpg\n Db.jpg\n Dc.jpg\n

正如hewgill在这里所指出的那样,shell然后将其拆分为三个令牌并将它们传递给echo;echo输出每个令牌,以空格分隔。要获得您想要的输出,请使用此处提供的不重新插入令人讨厌的令牌间空格的众多建议之一。

虽然比较冗长,但以下命令可以得到您想要的输出结果:
for file in "D"{a,b,c}".jpg"
do
  echo ${file}
done

感谢您的好解释! - Dan
太棒了的解释。我的解决方案是像ghostdog74建议的那样使用printf - Scott McAllister

5

echo 命令总是在参数之间添加空格。尝试不使用\n命令并比较结果。


3
不是echo在添加空格。尝试在命令行中输入"D"{a,b,c}".jpg"- 你会得到bash: Da.jpg: command not found。是大括号扩展添加了空格。 - James Polley
1
花括号扩展使用空格分隔参数;echo在参数之间添加一个空格。尝试使用大量空格在参数之间输入echo foo[space][space][space][space][space][space][space]bar - Greg Hewgill
2
Shell 在将参数列表传递给命令之前会去除它们之间的空格,而 echo 命令则会在参数之间添加一个空格(无论 echo 是 shell 内置命令还是外部命令)。这就是为什么 echo 会添加一个“额外”的空格,也是这个问题中所询问的。 - Greg Hewgill
1
这与大括号扩展无关。尝试以下命令,您仍将看到额外的空格 echo -e "D1.jpg\n" "D2.jpg\n" "D3.jpg\n" - R Samuel Klatchko
1
@James - 这只是花括号扩展的问题,因为花括号扩展会创建多个参数。但无论如何生成多个参数(显式地、使用通配符等),都会得到“额外”的空格。 - R Samuel Klatchko
显示剩余3条评论

3
最简单、最干净的解决方案是在每一行前面添加一个退格符:
echo -e -n "\bD"{a,b,c}".jpg\n"

这会产生所需的输出。

不是在我的Ubuntu Dapper机器上-第二行产生了“Db.jpg”,这是正确的,但第一行产生了“a.jpg”,这是不正确的。另一方面,在我运行Leopard的Mac上可以正常工作。 - James Polley
很奇怪... 在我的Ubuntu Karmic Koala机器上可以运行... 奇怪。 - mletterle
我想在Dapper和Koala之间解决了一些bug :) - James Polley
在Ubuntu中,将第一个条目添加一个空格即可使其工作: echo -en "" "\bD"{a,b,c}".jpg\n" - Dan
这仍然不是一个干净的解决方案。我猜如果你将它管道传输到一个不可倒带的设备上,它就无法工作了... - Algoman

2

使用xargs将第一个echo分离的参数分成每行一个,就可以获得所需的效果:

$ echo "D"{a,b,c}".jpg" | xargs -n1 echo
Da.jpg
Db.jpg
Dc.jpg

哦,好吃。我喜欢这比我的for循环好多了。 - James Polley

2

通过在前面添加 null,您可以获得更一致的外观:

$ echo -en "" "D"{a..c}".jpg\n"
 Da.jpg
 Db.jpg
 Dc.jpg

现在它们都有了额外的空格。此外,使用-n可以消除末尾多余的换行符。此外,您还可以在大括号扩展中使用范围。


0

这里有一个使用 sed 的解决方案(基于 https://dev59.com/gXI-5IYBdhLWcg3wI0p9#2003856):

$ echo -en "" "D"{a..c}".jpg\n" | sed 's/ //'
Da.jpg
Db.jpg
Dc.jpg

此解决方案的优点在于它可以处理包含空格的输入,例如:

$ echo -en "" "D "{a..c}".jpg\n" | sed 's/ //'
D a.jpg
D b.jpg
D c.jpg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接