I need to verify the size occupied by each user on my Linux server (all files recursively inside my data folder).

With the code below I can get all of my files and their users, but I don't know how to group and sum them after that.

#> find . -type f -ls | sort -k5

Does anyone has an idea to solve this problem ?

  • You will need to use something like awk to create a sum for each user, then output the names and sums. – Panki Jan 16 at 12:29
  • Note that disk usage (as reported by du) is not the same thing as file size (as reported by ls -l for instance). – Stéphane Chazelas Jan 16 at 21:33

With GNU find:

find . -printf '%D+%i:%u:%b\n' | awk -F: '
  !seen[$1]++ {du[$2] += $3}
  END {for (user in du) printf "%20s: %lu\n", user, du[user] * 512}'

That would report the disk usage in byte for each user. Like du does, it takes care not to count hard links several times.

find prints the device+inode number (%D+%i) for each file (for hard links to the same file, they would be identical), the user name and disk usage in number of 512-byte units.

: is used as the field separator as user names typically don't contain those as they are the field separator in the user database (like /etc/passwd or the output of getent passwd).

That list is fed to awk, where we update a du associative array indexed on the user's name ($2 the second field) for each of the files for which the first field has not already been seen.

At the END, we loop over the elements of the associative array to report the cumulative disk usage for each user (multiplying the number of blocks to get the information in bytes).

  • +1. This is faster than my script :-) I'm trying to learn, please explain the different parts of the command line. – sudodus Jan 16 at 22:17
  • @sudodus, see edit. – Stéphane Chazelas Jan 16 at 22:23
  • By the way, I checked and it seems to me that du (GNU coreutils) 8.28 in Ubuntu 18.04.1 LTS counts hardlinks only once. – sudodus Jan 16 at 22:52

This should work. It is a bit slow and it uses all users in your /etc/passwd, but that is easy to change and i'm not sure what kind of users you have (lastlog would also work I guess)

Note that this uses the current working directory (see the find .)

The oneliner:

for user in $(cut -d: -f1 < /etc/passwd); do echo -en "$user has:\t"; find . -user $user -type f -print0 | du --files0-from=- --total -sh | tail -n1 ; done

Here is the same, but a bit more verbose:

# Read all lines in /etc/password, use ":" as field separator and print first field
for user in $(cut -d: -f1 < /etc/passwd); do
  # Print username, -e to allow \t, -n to skip newline
  echo -en "$user is using:\t"
  # Find all files owned by $user, print found files to stdout and terminate
  # with a null character (thus circumventing the long file list problem).
  # let `du` read from null terminated stdin usint --files0-from=-, make a total,
  # make a summary and make it human readable, then only print the last line
  # containing the total
  find . -user "$user" -type f -print0 | du --files0-from=- --total -sh | tail -n1
  • +1: This is actually rather fast :-) – sudodus Jan 16 at 21:22

Computing the drive space occupied by the files owned by each user

This bash shellscript uses

  • find to find the owners
  • a for loop with a find command line to find all files belonging to each owner
    • and pipe the file names to du
  • after du the result is post-processed to make the result easy to read.

The shellscript is fairly fast, when tested in partitions with a lot of files.


# store owners in variable

if [ "$user" != "root" ]
 echo "Run with elevated permissions (as root or with sudo)"
elif ! test -d "$1"
 echo "Enter a target directory as parameter"

owners=$(find "$1" -printf "%u\n"|sort | uniq)
#echo "$owners"

for i in $owners
 if [ ${#i} -gt $leng ]

#echo "$leng"
skip=$((leng - 4))
spc=$(for ((i=0;i<skip;i++)); do printf " "; done)

printf "User $spc Size\n---- $spc ----\n"

for i in $owners
 skip=$((leng - ${#i}))
 spc=$(for ((i=0;i<skip;i++)); do printf " "; done)
 printf "$i $spc "
 find "$1" -type f -user "$i" -print0 | du --files0-from=- --total -sh |
  tail -n1 | cut -f 1

Demo examples

Assuming the name disk-usage-by-owner

ubuntu@ubuntu:~$ ./disk-usage-by-owner
Run with elevated permissions (as root or with sudo)
ubuntu@ubuntu:~$ sudo ./disk-usage-by-owner
Enter a target directory as parameter

Dialogue in a persistent live drive

ubuntu@ubuntu:~/bin$ sudo ./disk-usage-by-owner /cdrom
User  Size
----  ----
root  1.9G
ubuntu@ubuntu:~/bin$ sudo ./disk-usage-by-owner /home
User    Size
----    ----
root    0
ubuntu  1.9G
ubuntu@ubuntu:~/bin$ sudo ./disk-usage-by-owner /media/ubuntu/casper-rw
User              Size
----              ----
_apt              0
colord            44K
gdm               288K
man               628K
root              1007M
syslog            127M
systemd-timesync  0
ubuntu            1.9G

Hardlinks are counted only once

$ sudo find . -user root -ls
56492055 1024 -rw-r--r-- 3 root root 1048576 jan 16 23:41 ./owned\ by\ root\ hard-linked
56492055 1024 -rw-r--r-- 3 root root 1048576 jan 16 23:41 ./owned\ by\ root
56492055 1024 -rw-r--r-- 3 root root 1048576 jan 16 23:41 ./sub/owned\ by\ root

$ sudo ./disk-usage-by-owner .
User     Size
----     ----
root     1,0M
sudodus  32K

$ du .
4   ./sub
1064    .

This might be a little faster if you have the correct versions of find, stat and awk:

find . -type f -exec stat -c "%U %s" {} \; | awk '{sum[$1]+=$2} END {for (u in sum) {printf("%s: %d\n", u, sum[u])}}'

This will run the stat(1) command on all files found by the find(1) command. The stat will print out the user name and the size of the file. This will then passed to awk. The awk command just sums up all sizes for a given user for all files. Once all files have been processed, it will print out all users that are in the sum list, along with the total size of all of the files for that user.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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