15
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?

codeforester
  • 39,467
  • 16
  • 112
  • 140
xref
  • 1,707
  • 5
  • 19
  • 41

5 Answers5

12

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.

that other guy
  • 116,971
  • 11
  • 170
  • 194
kev
  • 155,172
  • 47
  • 273
  • 272
  • 6
    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. – jordanm Feb 18 '12 at 04:57
  • 5
    What's wrong with eval? Everything you do in bash is "dangerous", eval doesn't make things worse. – user123444555621 Feb 18 '12 at 13:17
  • 1
    @kev 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? – xref Feb 21 '12 at 17:23
  • 3
    That quote is talking about JScript (i.e. MS JavaScript). It's out of context here. – Grault Jun 05 '13 at 07:52
  • 1
    @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. – Charles Duffy Nov 09 '15 at 15:40
  • 2
    @Grault, it's certainly accurate even here; see above, and also BashFAQ #48 (http://mywiki.wooledge.org/BashFAQ/048). – Charles Duffy Nov 09 '15 at 15:41
  • @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. – dash-o Dec 10 '19 at 03:56
  • 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 damage – ychz Jun 14 '20 at 23:00
11

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
Cyrus
  • 84,225
  • 14
  • 89
  • 153
anubhava
  • 761,203
  • 64
  • 569
  • 643
10

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)
jfg956
  • 16,077
  • 4
  • 26
  • 34
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

.

Community
  • 1
  • 1
amit_g
  • 30,880
  • 8
  • 61
  • 118
1

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
Community
  • 1
  • 1
SiegeX
  • 135,741
  • 24
  • 144
  • 154