
Мне нужно проверить размер, занимаемый каждым пользователем на моем сервере 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 просто суммирует все размеры для данного пользователя для всех файлов. После обработки всех файлов она выведет всех пользователей, которые есть в списке сумм, вместе с общим размером всех файлов для этого пользователя.