10

I have a bunch of folders and I want to loop over all those folders and in each folder create another folder named "Photo"

F1
--F11
----F111
----F112
--F12

I want to have:

F1
--Photo
--F11
----Photo
----F111
------Photo
----F112
------Photo
--F12
----Photo
0

5 Answers 5

24

You can achieve it using a single find call.

find . -name 'Photo' -prune -o -type d -exec mkdir {}/Photo \;

The part -name 'Photo' -prune -o tells to not recurse to existing (and newly created) Photo directories: If the found file (or directory) has the name Photo, stop processing it (-prune). In the other case (-o), continue with directories (-type d) and execute (-exec) the command.

6
  • ah nice, I tried it that way and I see from your answer where I was going wrong :)
    – Zanna
    Sep 14, 2016 at 9:16
  • @Zanna -prune? :) Yes, it’s quite counter-intuitive but worth learning.
    – Melebius
    Sep 14, 2016 at 9:22
  • Will it stop creating a folder 'Photo' if a file named 'Photo' exists?
    – Anwar
    Sep 14, 2016 at 9:40
  • 3
    @Anwar The current version will. There is a grey zone in requirements. :) You can change this by specifying -type d together with -name 'Photo' before -prune.
    – Melebius
    Sep 14, 2016 at 9:43
  • 2
    @Anwar At second glance, it won’t make sense. You cannot create a folder with the same name as a regular file within the same folder. And find will continue with other folders (including subfolders of that folder, if you are asking for that).
    – Melebius
    Sep 14, 2016 at 10:31
10

You could pass find results to while instead of for since this way it won't break if the filenames have spaces

First cd to the directory F1, then do:

find -type d | while read dir ; do mkdir "$dir"/Photo ; done

If the directory exists, mkdir will just refuse to create it, so no problem there...

If your directory names could contain newlines, or other exotic strangeness, use this which can deal with arbitrary names:

find -type d -print0 | while IFS= read -r -d '' dir ; do mkdir "$dir"/Photo ; done

Thanks to @terdon for help with this :)

2
  • If the op's F1 directory is ~user/Pictures, moving to the parent directory and running the line will put a Photo directory in every directory in his space, which could be thousands. Consider adding the F1 as part of the commanline to avoid an easily made mistake. That way if it's inadvertently run from the wrong place, it won't create directories. Sep 14, 2016 at 12:18
  • ah yeah I actually was unsure of their directory structure. I suggest doing it from F1 instead, edited @L.D.James
    – Zanna
    Sep 14, 2016 at 12:23
8

From the directory just above F1 run this script:

The purpose of the script is to avoid having redundant photo directories created under photo directories.

Also, it's design to prevent accidentally running it from a wrong location such as the user's root directory, whereas it wouldn't see the F1 directory and mistakenly create hundreds of photo directories in the wrong palaces.

Also, it was my intentions to make an easy to follow script so the user could customize it.

#!/bin/bash

while IFS= read -r -d '' i;
do
    if [[ ! -d $i/Photo ]]; then
        # Filter to skip folders named Photo
        thisfolder="$(echo $i | sed "s/.*\///")"
        if [[ ! $thisfolder == "Photo" ]]; then
            mkdir "$i/Photo"
        fi
    fi
done < <(find F1 -type d -print0)

Script Updated:

  • Changed the lower case p in photo to upper case.
  • Added support for non-stander filesnames (with suggestions from Terdon).
12
  • 1
    I'd definitely avoid parsing ls, it can fail in unusual ways. I think the answers that avoid this are probably safer.
    – Arronical
    Sep 14, 2016 at 9:30
  • 3
    @Arronical ls isn't parsed. It's just feedback to the user... showing what is happening. Just like the words "This is a photo directory". It's letting the user know why it's not creating a directory there. Sep 14, 2016 at 9:34
  • 1
    I had thought that might be the case, as I couldn't see anything being done with it. In that case, I retract my comment and slope off :)
    – Arronical
    Sep 14, 2016 at 9:49
  • find -type d F1, maybe? Sep 14, 2016 at 11:28
  • Note that this will fail if there's a file (and not a directory) called $i/Photo, but the OP hasn't specified what should be done in such a case. It will also fail in the, admittedly unlikely case, where one of the $is contains a newline.
    – terdon
    Sep 14, 2016 at 14:04
5

Python with os.walk can do it fairly easily and in only a few lines of code

$ mkdir dir_one dir_two
$ mkdir dir_two/dir_three
$ python -c 'import os;[os.mkdir(r + "/Pictures") for r,d,f in os.walk(".")]'                 
$ tree
.
├── dir_one
│   └── Pictures
├── dir_two
│   ├── dir_three
│   │   └── Pictures
│   └── Pictures
└── Pictures

Explanation

What we're dealing with is this command: python -c 'import os;[os.mkdir(r + "/Pictures") for r,d,f in os.walk(".")]'

Here we simply call python interpreter with -c flag to specify the command we give within single quotes. os.walk() function allows us to recursively step through all subdirectories, and for each subdirectory (represented by r ) , we create Pictures folder via os.mkdir() function. r+"/Pictures" is just a simple string manipulation to join subdirectory string and "/Pictures" string together to form one path

Replace "/Pictures" with "/Photo" to fit your requirements

4

If you're using bash, you can simply run:

shopt -s globstar
for d in **/; do mkdir -p "$d"/Photo; done

The globstar option makes ** match "all files and 0 or more directories and subdirectories". In other words, it matches everything recursively. Because of the / at the end, **/ will match all directories and subdirectories (no files). Therefore, the $d will iterate over all directories in the current directory and their subdirectories and the Photos directory will be created in each of them.

The -p flag of mkdir means:

  -p, --parents
          no error if existing, make parent directories as needed

Here, I'm just using it to suppress error messages if the target directory already exists. Remove it if you want to see the errors.

Note that this will fail to create a Photo subdirectory in a target directory that contains a file named Photo. You haven't specified what should be done in those cases though and all other answers posted so far also have this limitation.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .