4

Is there any other short/easier and smarter way to do the following in Linux?

cd /home/abcd/dammi
mkdir $(date +%Y-%m)
cd $(date +%Y-%m)
mkdir $(date +%d)
# RESULT : /home/abcd/dammi/2011-05/26
cd /home/wxyz/harrami
mkdir $(date +%Y-%m)
cd $(date +%Y-%m)
mkdir $(date +%d)
cd /home/abcd/harrami
mkdir $(date +%Y-%m)
cd $(date +%Y-%m)
mkdir $(date +%d)
cd /home/wxyz/harrami
mkdir $(date +%Y-%m)
cd $(date +%Y-%m)
mkdir $(date +%d)

I need to use crontab to create folders every day and every month inside /home/abcd/dammi, /home/abcd/harrami, /home/wxyz/dammi and /home/wxyz/harrami. Can anyone help me with this?

Info:

    GROUPS : USERS
--------------------
    abcd  : abcd
    wxyz  : dammi, harrami

2 Answers 2

4

What about the following:

#!/bin/bash
HOME_DIRS="/home/abcd/dammi /home/wxyz/harrami /home/abcd/harrami /home/wxyz/harrami"
DATE_DIR=$(date +%Y-%m)
DAY_DIR=$(date +%d)

for FOLDER in $HOME_DIRS; do
    mkdir -p "${FOLDER}/${DATE_DIR}/${DAY_DIR}"
done

Well, of course you could also do it without DATE_DIR and DAY_DIR variables but this algorithm makes sure the date is not generated many times which is faster and assures the date to be the same for all users (even if you start it right before midnight and the last directory is created after midnight).

You might also have to think about enhancing the script using chown in order to allow users to write to the newly created directories.

Edit: If you want to create the same folder structure within two /home sub-folders you might combine the script of RolKau with my one:

#!/bin/bash
USER_LIST="dammi harrami"
HOME_SUBDIRS="abcd wxyz"
DATE_DIR=$(date +%Y-%m)
DAY_DIR=$(date +%d)

for HOME_SUBDIR in $HOME_SUBDIRS; do
    for U in $USER_LIST; do
        mkdir -p "/home/${HOME_SUBDIR}/${U}/${DATE_DIR}/${DAY_DIR}"
    done
done

Edit2: I assume the user list contains the user names. So let's extend the script so the directory owner is changed properly as well:

#!/bin/bash
USER_LIST="dammi harrami"
HOME_SUBDIRS="abcd wxyz"
DATE_DIR=$(date +%Y-%m)
DAY_DIR=$(date +%d)

for HOME_SUBDIR in $HOME_SUBDIRS; do
    for U in $USER_LIST; do
        mkdir -p "/home/${HOME_SUBDIR}/${U}/${DATE_DIR}/${DAY_DIR}"
        chown -R "${U}" "/home/${HOME_SUBDIR}/${U}/${DATE_DIR}"
    done
done

Edit3: To change the ownership I think the easiest way is to read the ownership from the directory at /home/<subdir>/<user>

#!/bin/bash
USER_LIST="dammi harrami"
HOME_SUBDIRS="abcd wxyz"
DATE_DIR=$(date +%Y-%m)
DAY_DIR=$(date +%d)

for HOME_SUBDIR in $HOME_SUBDIRS; do
    for U in $USER_LIST; do
        mkdir -p "/home/${HOME_SUBDIR}/${U}/${DATE_DIR}/${DAY_DIR}"
        GROUP_MEMBER=$(stat -c %G "/home/${HOME_SUBDIR}/${U}")
        chown -R "${U}":"${GROUP_MEMBER}" "/home/${HOME_SUBDIR}/${U}/${DATE_DIR}"
    done
done

Sure you could use stat as well to read the owner; but it's slightly slower than just reading it from the variable - as you asked for it:

#!/bin/bash
USER_LIST="dammi harrami"
HOME_SUBDIRS="abcd wxyz"
DATE_DIR=$(date +%Y-%m)
DAY_DIR=$(date +%d)

for HOME_SUBDIR in $HOME_SUBDIRS; do
    for U in $USER_LIST; do
        mkdir -p "/home/${HOME_SUBDIR}/${U}/${DATE_DIR}/${DAY_DIR}"
        OWNER=$(stat -c %U "/home/${HOME_SUBDIR}/${U}")
        GROUP_MEMBER=$(stat -c %G "/home/${HOME_SUBDIR}/${U}")
        chown -R "${OWNER}":"${GROUP_MEMBER}" "/home/${HOME_SUBDIR}/${U}/${DATE_DIR}"
    done
done

Edit4: Alternative solution using hard-coded group membership.

#!/bin/bash
USER_LIST="dammi:group1 harrami:group2"
HOME_SUBDIRS="abcd wxyz"
DATE_DIR=$(date +%Y-%m)
DAY_DIR=$(date +%d)

for HOME_SUBDIR in $HOME_SUBDIRS; do
    for UG in $USER_LIST; do
        G=${UG##*:}
        U=${UG%%:*}
        mkdir -p "/home/${HOME_SUBDIR}/${U}/${DATE_DIR}/${DAY_DIR}"
        GROUP_MEMBER=$(stat -c %G "/home/${HOME_SUBDIR}/${U}")
        chown -R "${U}":"${G}" "/home/${HOME_SUBDIR}/${U}/${DATE_DIR}"
    done
done

Edit5: Looking at your initial post the desired structure might be slightly different. I guess you want to have a sub-directory in /home for each group and only add user-directories for each group member. So here you go:

#!/bin/bash
USER_LIST="dammi:abcd dammi:wxyz harrami:wxyz"
DATE_DIR=$(date +%Y-%m)
DAY_DIR=$(date +%d)

for UG in $USER_LIST; do
    G=${UG##*:}
    U=${UG%%:*}
    mkdir -p "/home/${G}/${U}/${DATE_DIR}/${DAY_DIR}"
    chown -R "${U}":"${G}" "/home/${G}/${U}/${DATE_DIR}"
done

If a user is member in multiple groups just specify it multiple times in USER_LIST.

15
  • @SkyBeam yes the permission is causing problem now. how do i overcome it?
    – Himalay
    May 26, 2011 at 21:34
  • Just add another chown line - I've updated the answer to include chown as well. I guess you won't have to change the group ownership. If you have to, then just use 'chwon -R "${U}":groupname ...' instead.
    – SkyBeam
    May 26, 2011 at 21:42
  • @SkyBeam I have two different groups for those two users. Should I do it separately for this adding another for loop?
    – Himalay
    May 26, 2011 at 21:54
  • @SkyBeam actually there are three users and two group. I added in question above about that.
    – Himalay
    May 26, 2011 at 22:01
  • 1
    You can also get away with only one 'date' invocation: $(date "+%Y-%M/%d") May 27, 2011 at 13:46
3

Use the -p option to mkdir to create more than one element of the path at the time, and use a for-loop to avoid repeating yourself:

sh -c '
  for a in abcd wxyz; do 
    for b in dammi harrami; do 
      mkdir -p /home/$a/$b/$(date +%Y-%m)/$(date +%d); 
    done; 
  done
'

(line-breaks to show logical structure; could be all on one line)

3
  • Good answer. Even a bit faster than me. I like that you loop over home sub-directories too. However in his sample he creates 3 times "harrami" subfolders but dammi is not created within "wxyz" folder. Well, this might be a bug in the initial question though. You might also want to move the $(date) calls out of the loop. The date call is supposed to return the same value for each loop. $() issues a fork which can be very slow when used in loops.
    – SkyBeam
    May 26, 2011 at 21:23
  • 2
    You can also get away with only one 'date' invocation: $(date "+%Y-%M/%d") May 27, 2011 at 13:45
  • 1
    Multiple invocations of date are bad and should never be done due to a risk of date change. A theoretical bug is still very much a bug.
    – Asclepius
    Jun 29, 2015 at 20:49

You must log in to answer this question.

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