Рекурсивный вывод списка файлов, группировка по пользователю и суммирование их размера

Рекурсивный вывод списка файлов, группировка по пользователю и суммирование их размера

Мне нужно проверить размер, занимаемый каждым пользователем на моем сервере Linux (все файлы рекурсивно внутри моей папки с данными).

С помощью кода ниже я могу получить все свои файлы и их пользователей, но я не знаю, как их сгруппировать и просуммировать после этого.

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

Есть ли у кого-нибудь идеи по решению этой проблемы?

решение1

С 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}'

Это бы сообщило об использовании диска в байтах для каждого пользователя. Как и duделает, он заботится о том, чтобы не считать жесткие ссылки несколько раз.

findвыводит номер устройства и инода ( %D+%i) для каждого файла (для жестких ссылок на один и тот же файл они будут идентичны), имя пользователя и использование диска в количестве блоков по 512 байт.

:используется в качестве разделителя полей, поскольку имена пользователей обычно их не содержат, поскольку они являются разделителем полей в базе данных пользователей (например, /etc/passwdили выводе getent passwd).

Этот список передается в awk, где мы обновляем duассоциативный массив, индексированный по имени пользователя ( $2второе поле) для каждого из файлов, для которых первое поле еще не было seen.

В END, мы перебираем элементы ассоциативного массива, чтобы сообщить о совокупном использовании диска для каждого пользователя (умножая количествоблокидля получения информации в байтах).

решение2

Это должно работать. Это немного медленно и использует всех пользователей из вашего /etc/passwd, но это легко изменить, и я не уверен, какие у вас пользователи ( lastlogтоже сработает, я думаю)

Обратите внимание, что здесь используется текущий рабочий каталог (см. find .)

Однострочник:

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

Вот то же самое, но немного подробнее:

# 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
done

решение3

Вычисление дискового пространства, занимаемого файлами, принадлежащими каждому пользователю

Этот bashскрипт использует

  • findнайти владельцев
  • цикл forс findкомандной строкой для поиска всех файлов, принадлежащих каждому владельцу
    • и передайте имена файлов вdu
  • после того, как duрезультат будет обработан, чтобы сделать его удобным для чтения.

Скрипт оболочки работает довольно быстро при тестировании на разделах с большим количеством файлов.

#!/bin/bash

# store owners in variable

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

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

leng=0
for i in $owners
do
 if [ ${#i} -gt $leng ]
 then
  leng=${#i}
 fi
done

#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
do
 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
done

Демонстрационные примеры

Принимая имя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

Диалог в постоянном живом движении

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

Жесткие ссылки учитываются только один раз.

$ 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    .

решение4

Это может быть немного быстрее, если у вас правильные версии find, stat и 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])}}'

Это запустит команду stat(1) для всех файлов, найденных командой find(1). Stat выведет имя пользователя и размер файла. Затем это будет передано в awk. Команда awk просто суммирует все размеры для данного пользователя для всех файлов. После обработки всех файлов она выведет всех пользователей, которые есть в списке сумм, вместе с общим размером всех файлов для этого пользователя.

Связанный контент