How do I create a directory in all subdirectories?

Suppose I have a directory structure like this:

$ [~/practice] ls
a/ b/ c/ d/

Now I want to create a directory tmp1 in all sub directories of practice and I do this:

$ [~/practice] mkdir */tmp1
mkdir: cannot create directory `*/tmp1': No such file or directory

Then I try the -p switch and I endup with a directory named * with a sub directory tmp1

$ [~/practice] mkdir -p */tmp1

$ [~/practice] ls
*/ a/ b/ c/ d/

I know the use of -p switch is to create multiple nonexistent directories. I just thought it might help.

How do I create tmp1 in all subdirectories at once?

If this can be done, how do I extend it to create tmp1, tmp2, tmp3 in a, b and c at once?

Edit: I missed mentioning that the directories don’t have to be simple and in order, like a, b, c etc., and the directory to be created is not necessarily like tmp1, tmp2.

$ [~/practice] ls
dog/ cat/ rat/

In them, I would like to have something like

$ [~/practice] ls *
dog:
red/ blue/

cat:
red/ blue/

rat:
red/ blue/

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

With globs :

for dir in */; do mkdir -- "$dir/tmp1"; done

NOTE

  • I treat only dirs (including symlinks to dirs) with the little hack of using */ as a glob
  • If you want to create multiple subdirs at once :

    for dir in */; do mkdir -- "$dir"/{tmp1,foo,bar,qux}; done

Method 2

[…] how do I extend it to create tmp1, tmp2, tmp3 in a, b and c at once?

 mkdir {a,b,c}/tmp{1,2,3}

Method 3

With GNU or BSD* find:

find -mindepth 1 -maxdepth 1 -type d -exec mkdir {}/newdir ;

or using parameter expansion:

dirs=(*/)
mkdir -- "${dirs[@]/%/newdir}"

*Includes OS X

Method 4

Off topic since you’re mentioning bash, but for the record, with zsh, you’d do:

dirs=(*(/))
mkdir -- $^dirs/tmp1

$^var turns on brace-like expansion for the expansion of the array. It’s reminiscent of rc‘s ^ operator and in rc (or its derivative es), you’d write it:

dirs=(*/)
mkdir -- $dirs^tmp1

However note (and the same applies to the bash solutions given here) that in the rc solution dirs would also contain symbolic links to directories. In the zsh solution, change *(/) to *(-/) if you want to include symlinks to directories.

Method 5

Portably, loop over the parent directories:

for d in */; do mkdir "$d/red" "$d/blue"; done

Add -- after mkdir if you may have directories whose name starts with -.

In zsh, you can do it in a single command with the e glob qualifier:

mkdir *(/e''REPLY=($REPLY/{red,blue})'')

but it’s quicker to type this as two commands:

d=(*(/)); mkdir $^d/{red,blue}

Method 6

You can do that like that:

mkdir {a,b,c,d}/tmp1

Method 7

Variation on sputnick’s answer which avoids non-directory files:

for x in *; do if [ -d "$x" ]; then mkdir "$x/tmp1"; fi; done

Method 8

This is a good one from the old Unix Masters (tested on FreeBSD 10.1) if you want to version control (with RCS check in locked: ci -l with a brief comment as ir: for initial release) your /etc/* config files on ~/.his/etc

sudo rsync -av /etc/ ~/.his
sudo find -d ~/.his/etc -type d -exec echo '{}/RCS' ; | xargs sudo mkdir -p
sudo find -d ~/.his/etc ! -name "RCS" | xargs sudo ci -l -mir -t-ir

Method 9

Should be ! name “RCS” and it works best on the first check in.

sudo find ~/.his/etc ! -name “RCS” -ls

sudo find -d ~/.his/etc ! -name “RCS” | xargs sudo ci -l -mir -t-ir

This last one also works very well for the cjeck in part filtering all RCS content on the file name:

sudo find -d ~/.his/etc -type f | grep -v RCS | xargs sudo ci -l -mir -t-ir

Method 10

this is a great help to me. i had a need to create a set of subdirectories in multiple folders and something like:

!/bin/sh

cd /dest/cont

for dir in */*/; do
    mkdir -p -- $dir/{FB,Video,Audio,proj};
done

worked great except when a white space is encountered. is there a way to ignore spaces in the */*/ part of the arguments?


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x