Ubuntu – How to recursively make a directory in the last directories using the command line

command linedirectorymkdir

Let's say that I have the following directory structure where the name of the directories does not matter:

currentDir/
   Dir1
      Dir1
         Dir1 *
      Dir2 *
      Dir3 *
   Dir2
      Dir1 *
      Dir2 
         Dir1*
   Dir3*

Is there a way that I can create a directory named "Texture" in only the directories at the end of the tree branch (in the example they are marked with an *). I would like to make it so that only those directories get a Texture directory but not any others.

All directories may or may not have files, but the end directories will not have any other directories in them.

Best Answer

First turn on recursive globbing

shopt -s globstar

Now we can look in all directories with **. To unset, you can use shopt -u globstar (it's off by default, so it will be off when you open a new shell).

In all of the below, remove echo after testing to actually create the directories.

If the end-of-tree directories are empty, you could test for emptiness and make the directory only if it is detected... something like

for d in **/; do [[ -z "$(ls -Aq "$d")" ]] && echo mkdir "$d"Texture; done

i.e. if the output of ls -A (hidden files except current and parent dir) -q (printing ? for non-printing characters) is empty, make a directory.

But since the directories contain files, we'd better test that there are no directories

for d in **/; do [[ -z "$(find "$d" -maxdepth 1 -mindepth 1 -type d)" ]] && echo mkdir "$d"Texture; done

mindepth -1 is to stop the current directory being found... find sees hidden files, so we know those are included. Since any character should pass the test (we only want to check the output is empty), this should be fairly safe...

A more concise way (sorry Greg) (but actually all these methods do something similarly iffy - we can just about get away with using filenames as text since we aren't actually trying to do anything with those files themselves here):

for d in **/; do (ls -Alq "$d" | grep -q '^d') || echo mkdir "$d"Textures; done

here we add the -l flag for long output, which prints every file in the form

drwxrwxr-x 5 zanna zanna 4096 Sep 27 22:00 Dir1

we then gulp pipe that stuff into grep to see if any of the lines starts with d (meaning there's a directory). We don't want grep to print any of that meaningless unreliable text, so we just check its exit status with -q to see if it found anything. If it didn't, we make a directory (using the || or operator, meaning, do the next command if the last one failed). This should work, actually, even if your filenames contain horrible characters such as newlines, since ls prints them as ? - every line should start with a letter indicating the file type, so, probably, no kittens will die.