
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
ユーザー名 (2 番目のフィールド) でインデックス付けされた連想配列が更新されます。$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
ハードリンクは1回だけカウントされます
$ 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 コマンドは、指定されたユーザーのすべてのファイルのサイズを合計します。すべてのファイルが処理されると、合計リストにあるすべてのユーザーと、そのユーザーのすべてのファイルの合計サイズが出力されます。