递归列出文件,按用户分组并求和其大小

递归列出文件,按用户分组并求和其大小

我需要验证 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打印每个文件的设备+inode 号 ( %D+%i)(对于同一文件的硬链接,它们将是相同的)、用户名和磁盘使用情况(以 512 字节为单位)。

:用作字段分隔符,因为用户名通常不包含这些字段分隔符,因为它们是用户数据库中的字段分隔符(如/etc/passwd或 的输出getent passwd)。

该列表被馈送到awk,我们在其中为第一个字段尚未存在的每个文件更新du以用户名(第二个字段)为索引的关联数组。$2seen

在 处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

计算每个用户拥有的文件占用的驱动器空间

这个bashshell脚本使用

  • find寻找业主
  • for使用命令行循环查找find属于每个所有者的所有文件
    • 并将文件名通过管道传输到du
  • 对结果进行后du处理以使结果易于阅读。

在包含大量文件的分区中进行测试时,shell 脚本相当快。

#!/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])}}'

这将对 find(1) 命令找到的所有文件运行 stat(1) 命令。 stat 将打印出用户名和文件大小。然后这将传递给 awk。 awk 命令只是汇总给定用户的所有文件的所有大小。处理完所有文件后,它将打印出总列表中的所有用户,以及该用户的所有文件的总大小。

相关内容