0

I am trying to pass the variable $subdir which has the following string value :

subdir="subdir{1..5}/subdir{1..5}/subdir{1..5}/subdir{1..5}"

into the command mkdir in the following way :

mkdir -p $subdir

However, this is creating the following structure :

enter image description here

When I run this :

mkdir -p subdir{1..5}/subdir{1..5}/subdir{1..5}/subdir{1..5}

I get the structure that I want :

enter image description here

How do I make the command work while passing the path as a variable. I tried using quotes, but it doesn't work.

braX
  • 11,506
  • 5
  • 20
  • 33
Nishi K
  • 15
  • 8
  • [Please do not upload images of input/code/data/errors.](//meta.stackoverflow.com/q/285551) Use `tree` command output instead – Gilles Quénot May 07 '23 at 19:50
  • See ["How can I do brace expansion on variables?"](https://stackoverflow.com/questions/37270908/how-can-i-do-brace-expansion-on-variables) and the various linked Q&As. – Gordon Davisson May 07 '23 at 20:01
  • Parameter expansions are not subject brace expansions. Define an array containing the results of the brace expansion, or define a function that performs the brace expansion. – chepner May 07 '23 at 20:16

3 Answers3

2

Brace expansion need to be unquoted, so:

mkdir -p subdir{1..5}/subdir{1..5}/subdir{1..5}/subdir{1..5}

Check https://www.gnu.org/software/bash/manual/html_node/Brace-Expansion.html

If you really need a variable:

eval mkdir -p "$path"

warning Be sure that "$path" is not generated by CGI script, or by any random user input.

Gilles Quénot
  • 173,512
  • 41
  • 224
  • 223
  • @pjh Depends on what `"$path"` produces. The result is only quoted long enough to pass the quote-less string to `eval`. – chepner May 07 '23 at 20:17
0

The non-eval solution here is to use an array.

subdirs=( subdir{1..5}/subdir{1..5}/subdir{1..5}/subdir{1..5} )
mkdir -p "${subdirs[@]}"

This is a case of BashFAQ/050 - I'm trying to put a command in a variable, but the complex cases always fail! Syntax parsing, which handles things like Brace Expansion, comes before Parameter Expansion when bash evaluates the command line, so syntax characters inside of variables are going to be treated as literal data with no special meaning.

If you can't use this approach because the expansion isn't hardcoded for whatever reason, you can run a recursive function that doesn't rely on eval to do the work.

_f_mkdirs() {
  basename=$1
  levels=$2
  subdirs=$3

  # check the recursive exit condition
  if (( levels > 0 )) ; then
    # make however many directories at this level that you want
    for ((i=1 ; i <= subdirs ; i++)) ; do
      newdir="${basename}${i}"
      mkdir "${newdir}"
      # change into each directory and repeat the process until
      # you've descended to all levels
      # runs in a subshell to preserve current working state
      ( cd "${newdir}" && _f_mkdirs "${basename}" "$((levels-1))" "${subdirs}" )
    done
  fi
}
# to replicate your sample structure, call with: _f_mkdirs subdir 4 5 
tjm3772
  • 2,346
  • 2
  • 10
0
$ subdir=$(echo subdir{1..5}/subdir{1..5}/subdir{1..5}/subdir{1..5})
$ mkdir -p $subdir

$ var=$(echo subdir{1..2}/subdir{1..2}/subdir{1..2})
$ mkdir -p $var
$ tree
.
├── subdir1
│   ├── subdir1
│   │   ├── subdir1
│   │   └── subdir2
│   └── subdir2
│       ├── subdir1
│       └── subdir2
└── subdir2
    ├── subdir1
    │   ├── subdir1
    │   └── subdir2
    └── subdir2
        ├── subdir1
        └── subdir2

14 directories, 0 files
ufopilot
  • 3,269
  • 2
  • 10
  • 12