Rekursives Auflisten von Dateien, Gruppieren nach Benutzer und Summieren der Größe

Rekursives Auflisten von Dateien, Gruppieren nach Benutzer und Summieren der Größe

Ich muss die von jedem Benutzer auf meinem Linux-Server belegte Größe überprüfen (alle Dateien rekursiv in meinem Datenordner).

Mit dem folgenden Code kann ich alle meine Dateien und ihre Benutzer abrufen, aber ich weiß nicht, wie ich sie anschließend gruppieren und summieren kann.

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

Hat jemand eine Idee, um dieses Problem zu lösen?

Antwort1

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

Dadurch wird die Festplattennutzung in Byte für jeden Benutzer gemeldet. Dabei duwird darauf geachtet, dass Hardlinks nicht mehrfach gezählt werden.

finddruckt für jede Datei die Geräte- und Inode-Nummer ( %D+%i) (bei Hardlinks auf die gleiche Datei wären sie identisch), den Benutzernamen und die Festplattennutzung in Einheiten von 512 Byte.

:wird als Feldtrennzeichen verwendet, da Benutzernamen diese normalerweise nicht enthalten, weil sie das Feldtrennzeichen in der Benutzerdatenbank sind (wie /etc/passwdoder die Ausgabe von getent passwd).

Diese Liste wird an weitergeleitet awk, wo wir für jede Datei, für die das erste Feld noch nicht indiziert wurde, ein duassoziatives Array aktualisieren, das auf den Namen des Benutzers (das zweite Feld) indiziert ist .$2seen

Am ENDdurchlaufen wir die Elemente des assoziativen Arrays, um die kumulierte Festplattennutzung für jeden Benutzer zu ermitteln (durch Multiplikation der Anzahl derBlöckeum die Informationen in Bytes zu erhalten).

Antwort2

Das sollte funktionieren. Es ist etwas langsam und verwendet alle Benutzer in Ihrem /etc/passwd, aber das lässt sich leicht ändern und ich bin mir nicht sicher, welche Art von Benutzern Sie haben ( lastlogwürde wahrscheinlich auch funktionieren)

Beachten Sie, dass hierbei das aktuelle Arbeitsverzeichnis verwendet wird (siehe find .).

Der 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

Hier ist das Gleiche, aber etwas ausführlicher:

# 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

Antwort3

Berechnen des von den Dateien jedes Benutzers belegten Speicherplatzes

Dieses bashShellskript verwendet

  • findum die Besitzer zu finden
  • eine forSchleife mit einer findBefehlszeile, um alle Dateien zu finden, die jedem Besitzer gehören
    • und leiten Sie die Dateinamen weiter andu
  • nachdem dudas Ergebnis nachbearbeitet wurde, um es leichter lesbar zu machen.

Das Shellskript ist ziemlich schnell, wenn es in Partitionen mit vielen Dateien getestet wird.

#!/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

Demobeispiele

Den Namen annehmendisk-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

Dialog im permanenten 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 werden nur einmal gezählt

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

Antwort4

Dies geht möglicherweise etwas schneller, wenn Sie über die richtigen Versionen von find, stat und awk verfügen:

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

Dadurch wird der Befehl stat(1) für alle Dateien ausgeführt, die vom Befehl find(1) gefunden wurden. stat gibt den Benutzernamen und die Größe der Datei aus. Dies wird dann an awk übergeben. Der Befehl awk summiert einfach alle Größen für einen bestimmten Benutzer für alle Dateien. Sobald alle Dateien verarbeitet wurden, werden alle Benutzer ausgedruckt, die in der Summenliste enthalten sind, zusammen mit der Gesamtgröße aller Dateien für diesen Benutzer.

verwandte Informationen