Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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/
share|improve this question
1  
Given Christopher's answer, you should clarify whether "create \tmp1, \tmp2, \tmp3 in \a, \b and \c" should result a total of 3 or 9 subdirectories. –  manatwork Jan 20 '13 at 15:24
    
@manatwork: That's a good point. It should create 9 subdirectories. –  Nanda Jan 20 '13 at 15:27
add comment

7 Answers

up vote 14 down vote accepted

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

share|improve this answer
    
Could I do for i in */; do mkdir "$i/itemone" "$i/itemtwo"; done for multiple, not-in-order directory names? –  Nanda Jan 20 '13 at 15:36
    
I tested this and it is very much possible. Thanks. –  Nanda Jan 20 '13 at 15:39
    
See my edited post –  sputnick Jan 20 '13 at 15:42
1  
Brace expansion is not performed in quoted string. –  manatwork Jan 20 '13 at 16:13
    
Yes, thanks, post edited by Stephane Chazelas accordingly... –  sputnick Jan 20 '13 at 22:11
add comment

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.

share|improve this answer
    
+1 for your point about symlinks! This behavior may be desired, but mkdir's complaint about creating a duplicate directory can be suppressed with the -p flag. –  kojiro Jan 20 '13 at 21:46
add comment

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}
share|improve this answer
    
On a site that is meant to be a reference, I'd rather say "mkdir -- whatever, and omit -- if you intend for the expansion of whatever to be possibly taken as options to the mkdir command.". There's no point in omiting -- here. It may not be a problem in the OP's case, but it is one in the general case. I think we have a duty to teach the correct and safe syntax here. –  Stephane Chazelas Jan 21 '13 at 10:35
    
@StephaneChazelas In a scripting context, I always put all necessary -- and quotes and big fat warnings when newlines aren't supported. In a command line context, I prefer to show the quick version that works in practice first, and the bulletproof version as a complement. –  Gilles Jan 21 '13 at 11:06
add comment

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

share|improve this answer
1  
With standard find syntax: find . -name . -o -prune -type d -exec sh -c 'exec mkdir "$1/newdir"' sh {} \; –  Stephane Chazelas Jan 20 '13 at 22:04
    
Also note the differences between the two solutions: the first one includes hidden directories, the second one will add a newdir in the directories linked by any symlink in the current directory. –  Stephane Chazelas Jan 20 '13 at 22:06
add comment

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

for x in *; do if [ -d "$x" ]; then mkdir "$x/tmp1"; fi; done
share|improve this answer
    
I treat only dirs, that"s all the magic... –  sputnick Jan 20 '13 at 15:40
    
cool, got it ;) –  TAFKA 'goldilocks' Jan 20 '13 at 15:44
2  
Shouldn't that be if [ -d "$x" ];…? –  kojiro Jan 20 '13 at 21:43
    
Yes. I practically never have spaces in filenames and tend to forget that stuff... –  TAFKA 'goldilocks' Jan 21 '13 at 7:40
add comment

[...] 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}
share|improve this answer
add comment

You can do that like that:

mkdir {a,b,c,d}/tmp1
share|improve this answer
    
What if he has 100 directories? –  Bernhard Jan 20 '13 at 20:13
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.