Search code examples
linuxbashshellxargschown

Linux - Bash - apply chown within many user directories


I have about 400 users on /home/ directory.

I have a git repository on /var/repos/my_repo.git

I have cloned, using root account, this repository to all users on home folder through bash command.

Now I want to change the owner of cloned directory for each user, according to each folder.

Something like:

find . -maxdepth 1 -type d ! -name . -prune -exec chown {}:MY_GROUP {}/www/my_repo.git -R

It will not work because {} returns ./username, so I just need a way to clean ./

Somebody have a better solution?


Solution

  • There's a way to indirectly achieve what you want, provided your chown version supports the --reference option. In this case, the command:

    chown --reference=RFILE file_to_chown
    

    where RFILE and file_to_chown are two files (or directories), will change owner and group of file_to_chown to match that of RFILE.

    Since you want a special group, we'll need to use an auxilliary file that will be owned by user, and have group MY_GROUP. We'll use mktemp to create such a file.

    #!/bin/bash
    
    shopt -s nullglob
    
    rfile=$(mktemp) || { echo "oops"; exit 1; }
    
    for i in /home/*/; do
        [[ -d $i/www/my_repo.git ]] || continue
        chown --reference="$i" "$rfile"
        chown :MY_GROUP "$rfile" # or chgrp MY_GROUP "$rfile"
        chown -R --reference="$rfile" "$i/www/my_repo.git"
    done
    

    This method (using --reference) has the following advantage: a user's home name may be distinct from user's name.

    The exact same approach without the temporary file, using the my_repo.git in user's home as a reference file.

    #!/bin/bash
    
    shopt -s nullglob
    
    for i in /home/*/; do
        [[ -d $i/www/my_repo.git ]] || continue
        chown --reference="$i" "$i/www/my_repo.git"
        chown :MY_GROUP "$i/www/my_repo.git" # or chgrp MY_GROUP "$i/www/my_repo.git"
        chown -R --reference="$i/www/my_repo.git" "$i/www/my_repo.git"
    done
    

    As a final note: if you want to check how the script behaves before running it, you can define (inside the script, before the for loop) a function chown:

    chown() {
        echo "chown $@"
    }
    

    that will only show what's going to happen (minus the quotes), without executing anything. When you're happy, remove it from the script.