Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use an array to create subdirectories using mkdir in bash?

Tags:

arrays

bash

mkdir

I am trying to create a number of directories and subdirectories in one single command (ie avoiding for loops) like so:

mkdir -p {20..30}/{1..5}

This works no problem, and creates 10 directories, and inside each of them, it creates another 5. All good.

However I'd like to replace the subdirectories with an array, but this doesn't work as I expect.

For example, if I create:

tru=(1 2 3 4 5)

and do:

mkdir -p {20..30}/${tru[@]}

this is interpreted as

mkdir -p {20..30}/1 2 3 4 5

and only one subdirectory is created with name "1".

How can I make mkdir interpret my new array in a similar way to how it's doing with {1..5}?

like image 333
zapatilla Avatar asked Aug 31 '25 17:08

zapatilla


1 Answers

The working example you have there with mkdir -p {20..30}/{1..5} is a brace expansion. Implicit in the text produced by the shell expansion is a looping like behavior:

$ printf "mkdir -p %s\n" {1..3}/{10..12}
mkdir -p 1/10
mkdir -p 1/11
mkdir -p 1/12
mkdir -p 2/10
mkdir -p 2/11
mkdir -p 2/12
mkdir -p 3/10
mkdir -p 3/11
mkdir -p 3/12

The array expansion from ${array[@]} is something different:

$ arr=(10 11 12 13)
$ printf "mkdir -p %s\n" {1..3}/${arr[@]}
mkdir -p 1/10
mkdir -p 2/10
mkdir -p 3/10
mkdir -p 11
mkdir -p 12
mkdir -p 13

So the only way to get what you want (in Bash) is with an explicit loop.

If, for some reason, you need the same order in the cartesian product of the brace expansion, you need two loops:

for outer in {10..20}; do
    for inner in "${tru[@]}"; do
        mkdir -p "$outer/$inner"
    done
done

If you don't mind the order being different, you can do it in a single line:

$ for t in "${tru[@]}"; do mkdir -p {10..20}/"$t"; done

This loops through the outer first before the inner so the order is a little different. In this case, it does not matter.

like image 157
dawg Avatar answered Sep 02 '25 05:09

dawg