Listando arquivos recursivamente, agrupando por usuário e somando seu tamanho

Listando arquivos recursivamente, agrupando por usuário e somando seu tamanho

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 duforma, tome cuidado para não contar links físicos várias vezes.

findimprime 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/passwdou a saída de getent passwd).

Essa lista é alimentada awk, onde atualizamos um duarray associativo indexado no nome do usuário ( $2o 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 ( lastlogtambé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 bashshellscript usa

  • findpara encontrar os donos
  • um forloop com uma findlinha de comando para encontrar todos os arquivos pertencentes a cada proprietário
    • e canalize os nomes dos arquivos paradu
  • depois que duo 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.

informação relacionada