일일 스냅샷 폴더가 포함된 백업이 있습니다. 공간을 절약하기 위해 서로 다른 스냅샷에 있는 동일한 파일은 하드 링크(rsync로 생성됨)를 통해 중복 제거됩니다.
공간이 부족할 때 한 가지 옵션은 오래된 스냅샷을 삭제하는 것입니다. 그러나 하드 링크로 인해 특정 스냅샷을 삭제하여 얻을 수 있는 공간을 계산하기가 어렵습니다.
제가 생각할 수 있는 한 가지 옵션은 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}'
스냅샷 디렉토리에서 발견된 모든 링크를 찾은 후 링크 수가 0으로 떨어지는 파일의 디스크 사용량을 계산합니다.
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( )보다 큰 모든 파일을 가져옵니다. 선행 찾기의 잘린 부분을 인쇄합니다. 그런 다음 여러 링크가 있는 모든 파일을 제외하고 각 디렉터리의 디스크 사용량을 요청합니다. 물론, 스냅샷을 삭제하면 이전에는 두 개의 링크가 있었던 파일에 이제 하나의 링크만 있는 파일이 있을 수 있습니다. 따라서 몇 번 삭제할 때마다 다시 실행해야 합니다.-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"