Home > Software engineering >  Bash script: list all directories belonging to user and create file in each of them
Bash script: list all directories belonging to user and create file in each of them

Time:11-30

So I struggle only with part of task included in the title but my WHOLE task is to write linux bash script which is supposed to:

  1. read user name if user found, print their UID, default shell, print home directory and groups they belong to if user not found - create one with given $name
  2. for each user list directories they own together with these dir's access permissions
  3. in each of the listed directories (and subdirs) create file summary.txt containing list of its . directory and summarized size of dirs & files in this dir

So far I have this code: `

#! /bin/bash

echo "input username"
read name
awk -F':' -v name="$name" '$1==name { 
    print "uid: " $3 "\nhome directory: "$6 "\n default shell: "$7
    }' /etc/passwd

echo "belongs to groups:"
groups $name
#awk -F':' '{print }' /etc/group | grep $name

useradd -m $name 
#ls -lR ~/ $name | awk '{print $3 " "$9" "$1}' #it shows everything, files as well
echo -e "\n\n listing dirs which user owns:"
find / -type d -user $name -ls | awk '{print $11 "\t" $3}'

echo -e "\n\n creating files summary.txt:"
for dir in $(find / -type d -user $name -ls); 
    do ls > summary.txt; du -sh ./>> summary.txt; done;
#find . -type d -exec touch summary.txt {} \;

` Last lines is just one of many many tries and I see the FOR IN loop is invalid: it creates summary.txt file find-ls-times in the directory I run the script from and overwrites the previous summary all the time. I need it to create this file in each directory owned by $name, eg. after creating user "maria" the output (run as sudo) is:

uid: 1001 home dir: /home/maria default shell: /bin/sh belongs to groups: maria : maria useradd: user 'maria' already exists

listing dirs which user owns: find: ‘/run/user/1000/doc’: Permission denied find: ‘/run/user/1000/gvfs’: Permission denied /home/maria drwxr-x--- /home/maria/.config drwxr-xr-x /home/maria/.config/hexchat drwxr-xr-x /home/maria/.config/qt5ct drwxr-xr-x /home/maria/.config/caja drwxr-xr-x

creating files summary.txt: find: ‘/run/user/1000/doc’: Permission denied find: ‘/run/user/1000/gvfs’: Permission denied

P.S. I know I list only dirs of given $name instead of all users but that's a minor problem, I'd be glad for pointing out different errors tho. Thanks

CodePudding user response:

You can easily create a loop around most of the script to perform the logic for all the users you specify/choose (select by shared group, or selection of groups ?).

Not good practice to use the same variable name for both bash-level and AWK-level usage. It may confuse when reviewing code and make error messages ambiguous as to which is at fault.

Depending on what you want in the summary.txt files, you may wish to consider using a 'stat' report (format customizable):

find . -mindepth 1 -maxdepth 1 -user ${owner} \( ! -name 'summary.txt' \) -print0 | sed 's ^\./  ' | xargs -0 stat --format="|%F|%y|%a|%U|%G|%s|%n|"

I've added the -xdev option on the other find commands, in case you deploy users with access only to the disk on which they reside.

Other comments in the code.

#! /bin/bash

#QUESTION:  https://stackoverflow.com/questions/74620623/bash-script-list-all-directories-belonging-to-user-and-create-file-in-each-of-t

echo "input username"
read owner    

awk -F':' -v name="$owner" '$1==name { 
    print "uid: " $3 "\nhome directory: "$6 "\n default shell: "$7
    }' /etc/passwd

echo "belongs to groups:"
groups $owner
#awk -F':' '{print }' /etc/group | grep $owner

#useradd -m $owner 
#ls -lR ~/ $owner | awk '{print $3 " "$9" "$1}' #it shows everything, files as well

### Original command format
#find / -xdev -type d -user $owner -ls 2>>/dev/null > $$.tmp
#  6820719      4 drwxr-xr-x   5 ericthered ericthered     4096 Nov 17 15:30 /media/ericthered


### Do find only once, not multiple times
### Generate reverse sorted list, to facilitate visual progress towards beginning of list (if visually monitoring outputs).
### Also, want to control format of report to correctly identify dirname, 
###   otherwise AWK may later incorrectly report full filename if there is a $12, $13, etc.
### Output format:   inode permissions username groupname modified filesize filename
### FORMAT #1
#find / -xdev -type d -user $owner -printf "%i|%M|%u|%g|%Tb %Td %TY|%s|%p\n" 2>>/dev/null > $$.tmp
### FORMAT #2
find / -xdev -type d -user $owner -printf "%i|%M|%u|%g|%t|%s|%p\n" 2>>/dev/null | sort -nr > $$.tmp
head -10 $$.tmp

echo -e "\n\n listing dirs which user owns:"
### If having permissions in the report is significant, 
###   usually best to present so that "deviations" from norm are more self-evident, namely all lined up at begining.
awk -F \| '{ print $2 "\t" $7 }' $$.tmp

echo -e "\n\n creating files summary.txt:"
while read dir
do
    echo ${dir}
    ###  Must do cd into ${dir} to simplify directory-specific actions, and get correct results
    cd ${dir}

    ###  When some data is not same as the remainder in a file,
    ###    it is best to have that non-conforming data at the top for visibility.
    du -sh "${dir}" > summary.txt
    ls -l >> summary.txt
done < $$.tmp

### Unless specify a specific time value for touch,
###   touch time will vary from file to file.
### Use time of last summary file created for common reference (newest).
REFERENCE_FILE="$( tail -1 $$.tmp | awk -F\| '{ print $7 }' )/summary.txt"

printf "\n Setting '${REFERENCE_FILE}' as reference file for uniform timestamp ...\n"

### This find and exec is malformed.  -type will never find file to 'touch'.
#find / -type d -user ${owner} -exec touch summary.txt {} \;

find / -user ${owner} -name 'summary.txt' -print | xargs touch --reference="${REFERENCE_FILE}"
    
rm -f $$.tmp

CodePudding user response:

Here is how I would write your bash script, using getent and some GNU utils.

#!/usr/bin/env bash

IFS= read -rp 'Input_name: ' name

if IFS=: read -ra geckos_field < <(getent passwd "$name"); then
  printf 'uid: %s\nhome_directory: %s\ndefault_login_shell: %s\n' "${geckos_field[2]}" "${geckos_field[5]}" "${geckos_field[6]}"
else
  useradd -m "$name" || exit
  IFS=: read -ra geckos_field < <(getent passwd "$name") || exit
  printf 'uid: %s\nhome_directory: %s\ndefault_login_shell: %s\n' "${geckos_field[2]}" "${geckos_field[5]}" "${geckos_field[6]}"
fi

read -ra group_name < <(groups "${geckos_field[0]}") || exit

printf '\nUser %s belongs to group(s):\n' "${geckos_field[0]}"
printf '%s\n' "${group_name[@]:2}"

printf '\nDirectories for user %s:\n' "${geckos_field[0]}"
find "${geckos_field[5]}" -type d -printf "%p %M\n"

find "${geckos_field[5]}" -type d -exec bash -O nullglob -c '
  for f; do
    cd "$f" || exit;  du -sh "$f"/* > summary.txt
  done' _  {}  
  • Related