Brace expansion with a Bash variable - {0..$foo}
Asked Answered
E

5

16
WEEKS_TO_SAVE=4
mkdir -p weekly.{0..$WEEKS_TO_SAVE}

gives me a folder called weekly.{0..4}

Is there a secret to curly brace expansion while creating folders I'm missing?

Epiphenomenalism answered 18/2, 2012 at 0:56 Comment(0)
B
13

bash does brace expansion before variable expansion, so you get weekly.{0..4}.
Because the result is predictable and safe (don't trust user input), you can use eval in your case:

$ WEEKS_TO_SAVE=4
$ eval "mkdir -p weekly.{0..$((WEEKS_TO_SAVE))}"

note:

  1. eval is evil
  2. use eval carefully

Here, $((..)) is used to force the variable to be evaluated as an integer expression.

Broadway answered 18/2, 2012 at 4:21 Comment(9)
I almost downvotes this because of the use of eval. I would consider a C-sytle for loop the "proper" way, but this is the only way to accomplish it while running mkdir only once.Krefeld
What's wrong with eval? Everything you do in bash is "dangerous", eval doesn't make things worse.Bengt
@Broadway I googled 'eval is evil' and found: worthy scenarios make up a tiny percentage of the actual usage of eval. In the majority of cases, eval is used like a sledgehammer swatting a fly -- it gets the job done, but with too much power. It's slow, it's unwieldy, and tends to magnify the damage when you make a mistake. So is this a worthy case or are the other options listed here better?Epiphenomenalism
That quote is talking about JScript (i.e. MS JavaScript). It's out of context here.Brennan
@user123444555621, no, not everything you do in bash is dangerous. Parameter expansion happens after parsing for quotes, command substitution, redirection, etc; thus, data from expanding a parameter can't invoke new subcommands by including $(rm -rf /) or write to a file by including >/etc/passwd... unless you use eval, in which case that data is parsed as code.Synchronism
@Grault, it's certainly accurate even here; see above, and also BashFAQ #48 (mywiki.wooledge.org/BashFAQ/048).Synchronism
@CharlesDuffy From a practical point of view, 95%+ of the bash scripts that I see in real production environments are dangerous (not to mention buggy, ugly, not readable, ...). Trying to fight this by disallowing 'eval', is like fighting the ocean with a sand castle. The only real answer I've seen is to flip to programming environment that support more stricter grammar, error control.Dinorahdinosaur
I get that $((..)) would force it do arithmetic expansion, but why do we have to use $((WEEKS_TO_SAVE)) instead of simple $WEEKS_TO_SAVE, what could $WEEKS_TO_SAVE potentially damageAnesthesia
I wrote up a whole question to ask this, and only then did SE suggests this as a dupe which I couldn't find first time round. One other format I found that worked is export n=10 ; for i in eval echo {1..$n}` ; do echo $i.x ; done` or sticking the eval in with an echo.Aimo
M
12

Curly braces don't support variables in BASH, you can do this:

 for (( c=0; c<=WEEKS_TO_SAVE; c++ ))
 do
    mkdir -p weekly.${c}
 done
Mcclendon answered 18/2, 2012 at 1:5 Comment(0)
S
11

Another way of doing it without eval and calling mkdir only once:

WEEKS_TO_SAVE=4
mkdir -p $(seq -f "weekly.%.0f" 0 $WEEKS_TO_SAVE)
Strappado answered 18/2, 2012 at 11:45 Comment(1)
Boo, hiss; Doesn't work if you have whitespace or other characters in IFS in your format string.Synchronism
D
2

Brace expansion does not support it. You will have to do it using a loop.

Brace expansion is performed before any other expansions, and any characters special to other expansions are preserved in the result. It is strictly textual. Bash does not apply any syntactic interpretation to the context of the expansion or the text between the braces. To avoid conflicts with parameter expansion, the string ‘${’ is not considered eligible for brace expansion

.

Dupery answered 18/2, 2012 at 1:7 Comment(0)
M
2

If you happen to have zsh installed on your box, your code as written will work with Z-shell if you use #!/bin/zsh as your interpreter:

Example

$ WEEKS_TO_SAVE=4
$ echo {0..$WEEKS_TO_SAVE}
0 1 2 3 4
Mocha answered 18/2, 2012 at 5:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.