I know I can create a series of nested directories via a rather verbose series of mkdir -p
with the -p
flag applied to suppress warnings that the directory already exists. This gets very verbose with individual calls, i.e.:
mkdir -p hello
mkdir -p hello/i_am_a
mkdir -p hello/i_am_a/boy
mkdir -p hello/i_am_a/girl
mkdir -p hello/i_am_a/alien
mkdir -p hello/i_am_a/dog
mkdir -p hello/my_name_is
mkdir -p hello/my_name_is/jim
mkdir -p hello/my_name_is/bob
mkdir -p hello/my_name_is/secret
I would like to instead build the tree or at least part of it in a single call with a nested pattern consisting of a list-opening character (i.e. {
), list delimiter character (i.e. ,
)., and list-closing character (i.e. }
).
For each level starting with the top, a directory of that name is created if it does not exist already.
To continue my silly example above with real words, I would use the input string:
'hello{i_am_a{boy,girl,alien,dog},my_name_is{jim,bob,secret}}'
...which should create the following...
hello
hello/i_am_a
hello/i_am_a/boy
hello/i_am_a/girl
hello/i_am_a/alien
hello/i_am_a/dog
hello/my_name_is
hello/my_name_is/jim
hello/my_name_is/bob
hello/my_name_is/secret
For convenience, let's say that if it impacts the solution's length, we can assume there's no more than n
layers of nesting in the resultant tree (e.g. n=3
in my example above, for instance).
Let us further assume for convenience that the three special structure characters (in the above example, for instance {
, ,
, and }
) will never occur in the nested strings, i.e. they will never show up in the resulting file paths.
It seems a Perl
or Python
embedded script might do the trick, but perhaps there's a simpler solution using built-in BASH
functionality?
My goal is a concise solution that cuts down on the verbosity of my data post-processing scripts, which often involve the creation of hierarchical directory trees populated at deeper levels with intermediates that I save for reuse and with finished results in the directories towards the top of the tree.
Try this:
mkdir -p hello/{i_am_a/{boy,girl,alien,dog},my_name_is/{jim,bob,secret}}
seems to do the job:
find *
hello
hello/i_am_a
hello/i_am_a/dog
hello/i_am_a/alien
hello/i_am_a/boy
hello/i_am_a/girl
hello/my_name_is
hello/my_name_is/bob
hello/my_name_is/secret
hello/my_name_is/jim
... further?
This will create 30 files (named file_0a
to file_2j
) in each of this directories:
touch hello/{i_am_a/{boy,girl,alien,dog},my_name_is/{jim,bob,secret}}/file_{0..2}{a..j}
( For populating this 210 files, you could replace touch
by date | tee
, for sample. )
find * -ls | sed -ne '1,7{p;d};:;N;$!b;${s/^.*\(\(\n[^\n]*\)\{5\}\)\n*$/...\1/p;}'
1703938 4 drwxr-xr-x 4 user user 4096 avr 3 22:23 hello
1703939 4 drwxr-xr-x 6 user user 4096 avr 3 22:23 hello/i_am_a
1703943 4 drwxr-xr-x 2 user user 4096 avr 3 22:23 hello/i_am_a/dog
1704066 0 -rw-r--r-- 1 user user 0 avr 3 22:23 hello/i_am_a/dog/file_2i
1704057 0 -rw-r--r-- 1 user user 0 avr 3 22:23 hello/i_am_a/dog/file_1j
1704061 0 -rw-r--r-- 1 user user 0 avr 3 22:23 hello/i_am_a/dog/file_2d
1704052 0 -rw-r--r-- 1 user user 0 avr 3 22:23 hello/i_am_a/dog/file_1e
...
1704076 0 -rw-r--r-- 1 user user 0 avr 3 22:23 hello/my_name_is/jim/file_0i
1704097 0 -rw-r--r-- 1 user user 0 avr 3 22:23 hello/my_name_is/jim/file_2j
1704074 0 -rw-r--r-- 1 user user 0 avr 3 22:23 hello/my_name_is/jim/file_0g
1704073 0 -rw-r--r-- 1 user user 0 avr 3 22:23 hello/my_name_is/jim/file_0f
1704081 0 -rw-r--r-- 1 user user 0 avr 3 22:23 hello/my_name_is/jim/file_1d
... And as Jonathan Leffler suggest, have a look at man -Pless\ +/Brace.Expansion bash
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With