毎日のスナップショットフォルダを含むバックアップがあります。スペースを節約するために、異なるスナップショットにある同じファイルは、ハードリンク(rsyncで作成)を介して重複排除されます。
スペースが不足している場合の1つのオプションは、古いスナップショットを削除することです。ただし、ハードリンクのため、特定のスナップショットを削除して取得できるスペースを計算することは困難です。
私が考えることができる1つのオプションは、du -s
まずすべてのスナップショットフォルダに使用し、削除したフォルダを除くすべてのフォルダに使用することです。その違いにより、期待される確保空間を得ることができる。ただし、これは非常に面倒で、削除する正しいスナップショットを見つけようと繰り返し実行する必要があります。
より簡単な方法がありますか?
答えを心配して悩んだ終わりにスティーブン・チャジェラスそしてドロバート、私の質問が十分に正確ではないことに気づきました。より正確な試みは次のとおりです。
他のスナップショットのファイルと部分的に同じ(ハードリンク)保存されたファイルを含む一連のディレクトリ(「スナップショット」)があります。私は、スナップショットのリストとその中のファイルが占める使用されている各ディスクストレージの量を提供しますが、そのストレージが他のスナップショットのファイルでも使用されないようにするソリューションを探しています。各スナップショットにハードリンクが存在する可能性を許可したいと思います。
スペースが足りなくなったときにリストを見て、どのスナップショットを削除するかを決めることができるというアイデアです。これは、削除によって取得されたストレージスペースとスナップショット値(期間など)の間の妥協です。
答え1
GNUを使用して手動で実行できますfind
。
find snapshot-dir -type d -printf '1 %b\n' -o -printf '%n %b %i\n' |
awk '$1 == 1 || ++c[$3] == $1 {t+=$2;delete c[$3]}
END{print t*512}'
スナップショットディレクトリで見つかったすべてのリンクを見つけた後、リンク数がゼロになるファイルのディスク使用量を計算します。
find
印刷:
1 <disk-usage>
ディレクトリ用<link-count> <disk-usage> <inode-number>
他の種類のファイルの場合。
実際にはそうではなく、エントリが原因で発生し、そのエントリはリストされず、ディレクトリには通常他のハードリンクがないため、ディレクトリ内のリンクの数は常に1であると仮定し..
ますfind
。
この出力でawk
リンク数が 1 の項目のディスク使用量とその項目が表示された回数<link-count>
の inode を計算します (つまり、現在ディレクトリにすべてのハードリンクがある項目なのでリンク) - 削除された後にディレクトリツリーのスペースが 1 つに回収されます。
合計)スナップショット)を使用することもできますfind snapshot-dir1 snapshot-dir2
。
スナップショットディレクトリを削除するたびに節約されるスペースの量(累積方法)を知りたい場合は、次のことができます。
find snapshot-dir* \( -path '*/*' -o -printf "%p:\n" \) \
-type d -printf '1 %b\n' -o -printf '%n %b %i\n' |
awk '/:$/ {if (NR>1) print t*512; printf "%s ", $0; next}
$1 == 1 || ++c[$3] == $1 {t+=$2;delete c[$3]}
END{print t*512}'
スナップショットリストを語彙順に処理します。別の順序で処理する場合は、最後の番号(すべてのスナップショットが削除された場合)を除いて他の番号が付与されることがあります。
数字を読みやすくするを参照してくださいnumfmt
。
すべてのファイルが同じファイルシステムにあるとします。そうでない場合は、次のよう%i
に置き換えることができます(すべて同じファイルシステムにない場合は%D:%i
、とにかく削除できないマウントポイントがあることを意味します)。
答え2
ファイル名にパターン文字や改行文字が含まれていない場合は、find
+の除外機能を使用してdu
次のことができます。
find -links +1 -type f \
| cut -d/ -f2- \
| du --exclude-from=- -s *
このビットは、find
ハードリンク数が1()より大きいすべてのファイルを取得します。先行検索の切り捨て部分を印刷します。次に、複数のリンクを含むすべてのファイルを除き、各ディレクトリのディスク使用量を要求します。もちろん、スナップショットを削除すると、以前は2つのリンクがあったファイルに1つのリンクしかないファイルがある可能性があります。したがって、数回削除するたびに再実行する必要があります。-type f
-links +1
cut
./
du
任意のファイル名を使用する必要がある場合は、それを置き換えるためにさらにスクリプトが必要ですdu
(これはシェルモードなのでエスケープできません)。
さらに、Stéphane Chazelasが指摘したように、スナップショット内にハードリンクがある場合(すべてのファイル名はスナップショット間のハードリンクではなく単一のスナップショットに存在します)、そのファイルは完全に除外されます(スナップショットが削除されても)。スペースが復元されます)。
答え3
私がこの答えを書いた後、Stéphane Chazelasは彼の答えが正しいと私に確信させました。私はコードもうまく機能し、きれいな印刷機能を提供するので、コードを含む答えを残します。出力は次のとおりです。
total unique
--T---G---M---k---B --T---G---M---k---B
91,044,435,456 665,754,624 back-2018-03-01T06:00:01
91,160,015,360 625,541,632 back-2018-04-01T06:00:01
91,235,970,560 581,360,640 back-2018-05-01T06:00:01
91,474,846,208 897,665,536 back-2018-06-01T06:00:01
91,428,597,760 668,853,760 back-2018-07-01T06:00:01
91,602,767,360 660,594,176 back-2018-08-01T06:00:01
91,062,218,752 1,094,236,160 back-2018-09-01T06:00:01
230,810,647,552 50,314,291,712 back-2018-11-01T06:00:01
220,587,811,328 256,036,352 back-2018-11-12T06:00:01
220,605,425,664 267,876,352 back-2018-11-13T06:00:01
220,608,163,328 268,711,424 back-2018-11-14T06:00:01
220,882,714,112 272,000,000 back-2018-11-15T06:00:01
220,882,118,656 263,202,304 back-2018-11-16T06:00:01
220,882,081,792 263,165,440 back-2018-11-17T06:00:01
220,894,113,280 312,208,896 back-2018-11-18T06:00:01
どちらの回答も100%満足していないため(2018年11月18日現在)、両方の回答で学んだ内容にもかかわらず、独自のツールを作成してここに投稿しました。
〜のようにスティーブン・チャジェラスfind
答えは、inodeリストと関連ファイル/ディレクトリサイズを取得するために使用されますが、「最大1つのリンク」の経験的方法には依存しません。代わりに、各入力ディレクトリに固有のinodeリスト(ファイル/ディレクトリではありません!)を作成し、他のディレクトリからinodeをフィルタリングし、残りのinodeのサイズを合計します。このようにして、各入力ディレクトリの可能なハードリンクを説明できます。副作用として、入力ディレクトリのセット外の可能なハードリンクを無視します。
使用された Bash 外部ツール: find
、xargs
、mktemp
、sort
、tput
、awk
、tr
、 、numfmt
、touch
、cat
、comm
。rm
私も知っています。非常に軽くはありませんが、私が望む機能を正確に実行します。他の人が同様の要件を持っている場合に備えて、ここで共有しています。
より効率的または完璧にすることができるものがある場合は、コメントを残してください!私は確かにbashの専門家ではありません。
これを使用するには、次のコードをスクリプトファイルに保存しますduu.sh
。最初のコメントブロックには簡単な使用説明書が含まれています。
#!/bin/bash
# duu
#
# disk usage unique to a directory within a set of directories
#
# Call with a list of directory names. If called without arguments,
# it operates on the subdirectories of the current directory.
# no arguments: call itself with subdirectories of .
if [ "$#" -eq 0 ]
then
exec find . -maxdepth 1 -type d ! -name . -printf '%P\0' | sort -z \
| xargs -r --null "$0"
exit
fi
# create temporary directory
T=`mktemp -d`
# array of directory names
dirs=("$@")
# number of directories
n="$#"
# for each directory, create list of (unique) inodes with size
for i in $(seq 1 $n)
do
echo -n "reading $i/$n: ${dirs[$i - 1]} "
find "${dirs[$i - 1]}" -printf "%i\t%b\n" | sort -u > "$T/$i"
# find %b: "The amount of disk space used for this file in 512-byte blocks."
echo -ne "\r"
tput el
done
# print header
echo " total unique"
echo "--T---G---M---k---B --T---G---M---k---B"
# for each directory
for i in $(seq 1 $n)
do
# compute and print total size
# sum block sizes and multiply by 512
awk '{s += $2} END{printf "%.0f", s * 512}' "$T/$i" \
| tr -d '\n' \
| numfmt --grouping --padding 19
echo -n " "
# compute and print unique size
# create list of (unique) inodes in the other directories
touch "$T/o$i"
for j in $(seq 1 $n)
do
if [ "$j" -ne "$i" ]
then
cat "$T/$j" >> "$T/o$i"
fi
done
sort -o "$T/o$i" -u "$T/o$i"
# create list of (unique) inodes that are in this but not in the other directories
comm -23 "$T/$i" "$T/o$i" > "$T/u$i"
# sum block sizes and multiply by 512
awk '{s += $2} END{printf "%.0f", s * 512}' "$T/u$i" \
| tr -d '\n' \
| numfmt --grouping --padding 19
# append directory name
echo " ${dirs[$i - 1]}"
done
# remove temporary files
rm -rf "$T"