9

In zsh (and other shells), if I include an argument like (for example):

{a,b,c}{d,e,f}

brace expansion turns it into:

ad ae af bd be bf cd ce cf

For my purposes, the argument order is important, and I need the braces to expand right-to-left instead of left-to-right. That is, I want the expansion to be:

ad bd cd ae be ce af bf cf

Is there a way to control the order that multiple sets of braces are expanded? I'm looking for something that will work in any situation, not just with these arguments.

  • I assume you're not interested in more complex solutions involving loops or sorted output, right? – terdon Nov 22 '15 at 16:54
  • @terdon If there's no other way I suppose; I was hoping there was some trick to change the order of evaluation of brace expansion, but there probably isn't. Those arguments were just an example though, so something that only works for {a,b,c}{d,e,f} isn't very helpful – Michael Mrozek Nov 22 '15 at 17:21
  • Yeah, I guessed as much. You might want to make that clear though to avoid answers based on sorting order. – terdon Nov 22 '15 at 17:36
8

You can combine parameter expansion with brace expansion.

% foo=(d e f)
$ echo {a,b,c}${^foo}
ad bd cd ae be ce af bf cf

If you don't want to define foo separately (as seems likely), you can use the following:

$ echo {a,b,c}${^:-d e f}
ad bd cd ae be ce af bf cf

If you have the rcexpandparam option set, then you don't need the ^ in either example to enable this behavior.

(Note: while testing, I also had the shwordsplit option set. If you don't have it set, then try, for example echo {a,b,c}${^=:-d e f}. Moral of the story: almost anything is possible in zsh, but you have to make sure you are using the correct combination of options and syntax.)

  • 1
    You should use print -- {a,b,c}${^=:-d e f} as the main example, since when split+glob was turned off by default in zsh. – cuonglm Nov 23 '15 at 2:09
4

In zsh you can use the -C specified number of columns argument to print like:

print $(print -C3 {a,b,c}{d,e,f})

...to get...

ad bd cd ae be ce af bf cf

...without the $IFS splitting the following:

print -C3 {a,b,c}{d,e,f}

...prints...

ad bd cd
ae be ce
af bf cf

...but you can do that across before down like...

print -aC3 {a,b,c}{d,e,f}

ad ae af
bd be bf
cd ce cf

...or...

print $(print -aC2 {foo,bar}{bad,baz})

foobad foobaz barbad barbaz
  • That produces the same output that MIchael is trying to avoid. He wants 1.1 2.1 3.1 and you are giving 1.1 1.2 1.3 (if that's clear). – terdon Nov 22 '15 at 16:53
  • @terdon - good point. – mikeserv Nov 22 '15 at 17:07
  • I am guessing (though not explicitly stated) that Michael is after the specific order of pairing. Your approach only works if the elements can be sorted alphabetically. What about getting foobad foobaz barbad barbaz from {foo,bar}{bad,baz}`? – terdon Nov 22 '15 at 17:12
  • @terdon - well, if that's what he's after then why not say so? and anyway, the columns can be paired any which way if you do the math. – mikeserv Nov 22 '15 at 17:13
  • 1
    @terdon - you moderators seem to make it a habit of saying what you don't mean. – mikeserv Nov 23 '15 at 21:38
2

You can put number at the end of each element of second set and then sort on last character:

echo -e "\n"{a,b,c}{d1,e2,f3} | sort -k 1.3 | cut -c 1-2 | tr '\n' ' '

Even better would be to add numbers after some separator (space), to cut fields, not characters:

echo -e "\n"{a,b,c}{"d 1","e 2","f 3"} | sort -k 2n | cut -f 1 -d ' ' -s | tr '\n' ' '
1

In fish shell, you have that behavior by default, since expansion in fish is performed right-to-left:

$ fish -c 'echo {a,b,c}{d,e,f}'
ad bd cd ae be ce af bf cf

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.