
Preciso verificar o tamanho ocupado por cada usuário no meu servidor Linux (todos os arquivos recursivamente dentro da minha pasta de dados).
Com o código abaixo consigo obter todos os meus arquivos e seus usuários, mas não sei como agrupá-los e somá-los depois disso.
#> find . -type f -ls | sort -k5
Alguém tem uma idéia para resolver esse problema?
Responder1
Com 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}'
Isso reportaria o uso do disco em bytes para cada usuário. Da mesma du
forma, tome cuidado para não contar links físicos várias vezes.
find
imprime o número do dispositivo + inode ( %D+%i
) para cada arquivo (para links físicos para o mesmo arquivo, eles seriam idênticos), o nome de usuário e o uso do disco em número de unidades de 512 bytes.
:
é usado como separador de campos, pois os nomes de usuário normalmente não os contêm, pois são o separador de campos no banco de dados do usuário (como /etc/passwd
ou a saída de getent passwd
).
Essa lista é alimentada awk
, onde atualizamos um du
array associativo indexado no nome do usuário ( $2
o segundo campo) para cada um dos arquivos para os quais o primeiro campo ainda não existiu seen
.
No END
, percorremos os elementos da matriz associativa para relatar o uso cumulativo do disco para cada usuário (multiplicando o número deblocospara obter as informações em bytes).
Responder2
Isso deve funcionar. É um pouco lento e usa todos os usuários em seu /etc/passwd, mas isso é fácil de mudar e não tenho certeza de que tipo de usuários você tem ( lastlog
também funcionaria, eu acho)
Observe que isso usa o diretório de trabalho atual (veja o find .
)
O 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
Aqui é o mesmo, mas um pouco mais detalhado:
# 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
Responder3
Calculando o espaço em disco ocupado pelos arquivos de propriedade de cada usuário
Este bash
shellscript usa
find
para encontrar os donos- um
for
loop com umafind
linha de comando para encontrar todos os arquivos pertencentes a cada proprietário- e canalize os nomes dos arquivos para
du
- e canalize os nomes dos arquivos para
- depois que
du
o resultado é pós-processado para facilitar a leitura do resultado.
O shellscript é bastante rápido quando testado em partições com muitos arquivos.
#!/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
Exemplos de demonstração
Assumindo o nomedisk-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
Diálogo em uma unidade ao vivo persistente
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 são contados apenas uma vez
$ 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 .
Responder4
Isso pode ser um pouco mais rápido se você tiver as versões corretas de find, stat e 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])}}'
Isso executará o comando stat(1) em todos os arquivos encontrados pelo comando find(1). O stat imprimirá o nome de usuário e o tamanho do arquivo. Isso será então passado para o awk. O comando awk apenas resume todos os tamanhos de um determinado usuário para todos os arquivos. Depois que todos os arquivos forem processados, todos os usuários que estão na lista de soma serão impressos, junto com o tamanho total de todos os arquivos desse usuário.