tags:

views:

355

answers:

6

I get:

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

Note: The extra spaces before Db and Dc on the 2nd and 3rd line of the output.

Why are these there?

Thanks, Dan

Edit: Since my actual objective had spaces in it (which I should have written originally):

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

Most solutions here didn't work for me (for loop, xarg, tr). Printf didn't work because of multiple braces expansions that I want to cantesian product.

I combined 3 solutions (mletterle's \b, Dennis Williamson's extra space, and Jim Dennis's using far less quotes) to get:

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

Thanks all who answered! I learned a lot from your responses!

Dan

+4  A: 

echo always adds spaces between arguments. Try your command without \n and compare the results.

Greg Hewgill
It's not `echo` adding the spaces. Try just `"D"{a,b,c}".jpg"` at the commandline - you'll get `bash: Da.jpg: command not found`. It's the brace expansion adds the spaces.
James Polley
Brace expansion separates the arguments with whitespace; echo adds one space between arguments. Try `echo foo[space][space][space][space][space][space][space]bar` with a whole bunch of spaces between arguments.
Greg Hewgill
... correct, but irrelevant. but the problem here is that brace expansion is adding a single space that Dan doesn't want. `echo` isn't adding or subtracting anything.
James Polley
The *shell* removes whitespace between arguments before passing the argument list to the command, and echo adds *one space* back in between arguments (regardless of whether echo is a shell builtin or an external command). This is the reason why echo is adding an "extra" space, which is what the question asked.
Greg Hewgill
I was wrong, and you are correct. The shell indeed removes the spaces when it tokenizes, and echo adds them back. This still doesn't lead to a working outcome though.
James Polley
This has nothing to do with brace expansion. Try the following and you'll still see the extra spaces `echo -e "D1.jpg\n" "D2.jpg\n" "D3.jpg\n"`
R Samuel Klatchko
It does have to do with brace expansion; if brace expansion didn't add the spaces, echo would see only a single token (ie, the equivalent of `echo -e "D1.jpg\n""D2.jpg\n""D3.jpg\n"`, which produces the desired output
James Polley
@James - it's only an issue of brace expansion in that brace expansion creates multiple arguments. But regardless of how multiple arguments are generated (explicitly, with wild cards, etc.) you get the 'extra' space.
R Samuel Klatchko
+7  A: 

Because that's what brace expansion does. From man bash, under the heading Brace expansion:

Patterns to be brace expanded take the form of an optional preamble, followed by ... a series of comma-separated strings ... followed by an optional postscript. The preamble is prefixed to each string contained within the braces, and the postscript is then appended to each resulting string, expanding left to right For example, a{d,c,b}e expands into ‘ade ace abe’

So in your example, "D" is the preamble and ".jpg\n" is the postscript.

So, after brace expansion occurs, you're left with:

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

As hewgill points out, the shell then splits this into three tokens and passes them to echo; which outputs each token separated by a space. To get the output you want, you need to use one of the many suggestions here that don't re-inserted the unwanted space between tokens.

It's longer and probably not the neatest way to do this, but the following gives the output you're after:

for file in "D"{a,b,c}".jpg"
do
  echo ${file}
done
James Polley
Thanks for the great explination!
Dan
+2  A: 

You can get the desired effect by using xargs to separate the arguments spit by the first echo into a line each:

$ echo "D"{a,b,c}".jpg" | xargs -n1 echo
Da.jpg
Db.jpg
Dc.jpg
alvherre
Oooh, tasty. I like this much better than my for loop.
James Polley
+1  A: 

The easiest and cleanest solution is to add a backspace to the front of each line:

echo -e -n "\bD"{a,b,c}".jpg\n"

This produces the desired output.

mletterle
not on my ubuntu dapper machine - this gives `Db.jpg` for the second line, which is correct, but `a.jpg` for the first line, which is not. On the other hand, it works on my mac running Leopard.
James Polley
That's odd.. it works on my ubuntu karmic koala machine... weird.
mletterle
I imagine a few bugs were fixed between Dapper and Koala :)
James Polley
In Ubuntu, adding a space to the first entry makes it work: echo -en "" "\bD"{a,b,c}".jpg\n"
Dan
+4  A: 

use the more portable printf

$ printf "D%s.jpg\n" {a,b,c}
Da.jpg
Db.jpg
Dc.jpg
ghostdog74
+1  A: 

You can get a more consistent look by prepending a null:

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

Now they all have an extra space. Also, using -n eliminates the extra newline at the end. Also, you can use a range in your brace expansion.

Dennis Williamson