Execute command multiple times with curly brackets arguments list
Asked Answered
G

3

13

When I needed to run a command multiple times with a different argument I used this approach (without understanding it fully):

touch {a,b,c}

Which is equivalent of:

touch a
touch b
touch c

I think the same could be accomplished with the following loop:

for file in {a,b,c}; do touch $file; done

However I've stumbled across a case where this does not work:

pear channel-discover {"pear.phpunit.de","pear.symfony-project.com"}

I have a few questions:

  1. What is the name of what is happening in the first example and what exactly is happening?
  2. Is it better to use this approach for simple things rather than for-in loops?
  3. Why the pear command is not working like that? Should the command script implement some techniques to handle such arguments or is it the shell responsible for that?
Goring answered 20/12, 2012 at 12:3 Comment(0)
M
14

That's called Brace Expansion, which expands to a space-separated list of the given strings.

So touch {a,b,c} would be equivalent to

touch a b c

While touch {a,b,c}x would be equivalent to:

touch ax bx cx

You pear command would essentially be run as:

pear channel-discover pear.phpunit.de pear.symfony-project.com

which may not be what you expected. If you want the command to be run once for each string, use a for loop (which answers your 2nd question), or use a combination of brace expansion and xargs.

Matrona answered 20/12, 2012 at 12:19 Comment(2)
@Shawin Chin, you are right. I was expecting multiple executions of the command and not just expanding the arguments list. The link you've provided for Brace Expansion is very helpful.Goring
I made the same mistake before, so I'm glad I could help you out.Matrona
I
6

The problem is that contrary to your expectation, the brace expansion of

touch {a,b,c}

is equivalent to

touch a b c   # NOT 3 separate invocations.

(Use echo {a,b,c} to verify). It appears that pear channel-discover does not accept two args. You will probably see the same error with

pear channel-discover pear.phpunit.de pear.symfony-project.com
Irkutsk answered 20/12, 2012 at 12:19 Comment(2)
is there a bash notation that does perform multiple invocations?Marilyn
No; that "notation" would be a loop like for i in a b c; do ...; doneIrkutsk
W
0

Well, you have two options:

for i in "pear.phpunit.de" "pear.symfony-project.com"
do
  pear channel-discover "$i"
done

Or a one-liner (but calling xargs instead of using bash internals):

echo "pear.phpunit.de" "pear.symfony-project.com" | xargs -n1 pear channel-discover

The former is certainly easier to read by the human, the time efficiency will be basically the same.

Worthen answered 9/9, 2014 at 14:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.