11

I am trying to make a directory tree from A to Z where the next directory is within the current directory.

For example: B is within A and C is within B and so on..

-A
--B
---C
----...Z

Any clues on how to get it done the automated way?

David Foerster
  • 35,754
  • 55
  • 92
  • 145
Nish
  • 111
  • 3
  • I wonder what’s the practical purpose of such directories. IMHO this looks more like a question for [codegolf.se]. – Melebius Apr 10 '18 at 09:33
  • 3
    @Melebius One possible purpose is to create a directory structure as a test case, in order to help verify that some other command, script, or application works property. Here's [a recent instance](https://askubuntu.com/q/1023244) where the question itself wasn't about creating specific directory structures, but knowing how to write commands to do so was useful for testing purposes, not in spite of how the specific structure was contrived and weird, but because of it. (We do also have many questions about creating specific directory structures, which can be found by searching for "`mkdir -p`".) – Eliah Kagan Apr 10 '18 at 13:11

3 Answers3

25

With mkdir, printf and bash's brace expansion:

$ mkdir -p "$(printf "%s/" {A..Z})"
$ tree A
A
└── B
    └── C
        └── D
            └── E
                └── F
                    └── G
                        └── H
                            └── I
                                └── J
                                    └── K
                                        └── L
                                            └── M
                                                └── N
                                                    └── O
                                                        └── P
                                                            └── Q
                                                                └── R
                                                                    └── S
                                                                        └── T
                                                                            └── U
                                                                                └── V
                                                                                    └── W
                                                                                        └── X
                                                                                            └── Y
                                                                                                └── Z

25 directories, 0 files
  • {A..Z} expands to A B ... Z,
  • printf "%s/" prints the arguments with a / after them, so I get A/B/...Z/
  • and mkdir -p creates the A/B/.../Z directory with any parent directories that needed creating.
Volker Siegel
  • 12,820
  • 5
  • 48
  • 65
muru
  • 193,181
  • 53
  • 473
  • 722
  • thanks for that. Thought I get this error while . I use the command mkdir: A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y: No such file or directory – Nish Apr 10 '18 at 06:08
  • 3
    @Nish There's a `-p` in the `mkdir` command. – muru Apr 10 '18 at 06:09
  • my bad, i tried that on my mac instead of ubuntu. And a follow up question is this--> let's say I wanted to have A1..A100 directory within A (in the same structure AtoZ). Then B1..B100 within B. So it looks something like this --> imgur.com/jfuKEdf – Nish Apr 10 '18 at 06:17
  • 11
    Let's say you post a follow-up as an actual question instead of in the comments, and didn't use images but text. That would be much better, no? – muru Apr 10 '18 at 06:25
  • I understand your point here. Its difficult to post it as its not a code and its a hugeass output at that. So simply looking at the screenshot makes it easier to understand. – Nish Apr 10 '18 at 06:29
  • @Nish you can shorten the output by showing the beginning and the end only, right? And please, do not post screenshots or images of text, that's just... cruel. But useful images can be shown inline. And: Welcome at StackExchange! – Volker Siegel Apr 10 '18 at 09:02
  • It works in zsh just the same as in bash. – Volker Siegel Apr 10 '18 at 09:11
  • this was the simplest solution i could get! – ptetteh227 Apr 28 '18 at 17:48
7

At the very simple level, you could make use of {A..Z} expansion to generate all the letter, then iteratively make and enter each one:

~/test_directory$ for d in {A..Z}; do mkdir "$d"; cd "$d"; done
~/test_directory/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z$ 

As you can see in my prompt output, now you have completely chained directory.

However, if actual directory names are different than just alphabet, you'll have to somehow provide the list of directory names, perhaps via a file, over which you iterate and do same process again. Basically, this

while IFS= read -r dir_name;do mkdir "$dir_name"; cd "$dir_name" ;done < directory_list.txt
Sergiy Kolodyazhnyy
  • 103,293
  • 19
  • 273
  • 492
  • thats pretty cool. Here's a followup question. let's say I wanted to have A1..A100 directory within A (in the same structure AtoZ). Then B1..B100 within B. So it looks something like this --> https://imgur.com/jfuKEdf – Nish Apr 10 '18 at 06:10
  • @Nish ah, that'd require an inner loop so `for d in {A..Z}; do mkdir "$d"; cd "$d"; for i in {1..100}; do mkdir "${d}${i}" ;done ; done` – Sergiy Kolodyazhnyy Apr 10 '18 at 06:15
  • Or even without inner loop, `for d in {A..Z}; do mkdir "$d"; cd "$d"; mkdir "$d"{1..100}; done` – Sergiy Kolodyazhnyy Apr 10 '18 at 06:17
  • thanks for that. It seems to work but the order of the directory seem screwed up so 2 is not after 1. Its sorted randomly. Anyway to fix that? Here's a screenshot --> https://imgur.com/a/Zqj1c – Nish Apr 10 '18 at 06:22
  • @Nish Sorting order is text-based, not numerical as I think you expect. As far as `tree`, I'm not sure how to fix that, but I think this might not even be `tree`'s problem, but rather shell's sorting order. I'd suggest asking actual question about that either here or better yet on unix.stackexchange.com – Sergiy Kolodyazhnyy Apr 10 '18 at 07:05
  • @Nish, probably you are asking for a command as: `ls -1v --group-directories-first` or `ls -lv --group-directories-first`. – pa4080 Apr 10 '18 at 14:13
2

Even though muru's printf way can't be beat, I personally like jot for this sort of thing. jot isn't installed by default in Ubuntu. The athena-jot package provides it. Either of these commands works:

mkdir -p "$(jot -s/ -c 26 A)"
jot -s/ -c 26 A | xargs mkdir -p

Really any command that generates the sequence of letters and joins them with slashes will facilitate this, because its output can then be passed to mkdir -p either through command substitution (as in muru's answer) or using xargs. Here are some examples using a few tools and xargs that don't require that you install software, except perhaps on very minimal systems or Ubuntu Core:

perl -we 'print join "/", A..Z' | xargs mkdir -p
ruby -we 'print (?A..?Z).to_a * ?/' | xargs mkdir -p
python3 -c 'print("/".join(__import__("string").ascii_uppercase))' | xargs mkdir -p

Old Ubuntu releases come with Python 2 instead of Python 3. For that, just change python3 to python to make that last command work, if you really want to do this with Python.

Similarly, muru's short and simple way can alternatively be written:

printf '%s/' {A..Z} | xargs mkdir -p

The trailing /, in the directory path mkdir -p is asked to create, is no problem and arguably is stylistically preferable. But it's fine to omit it, as the other examples in this answer do.

Eliah Kagan
  • 116,445
  • 54
  • 318
  • 493