Вы можете сделать это вручную с помощью GNUfind
:
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>
для других типов файлов. Мы делаем вид, что количество ссылок всегда равно единице для каталогов, потому что на практике это не так из-за записей ..
, а find
не перечисляет эти записи, а каталоги обычно не имеют других жестких ссылок..
Из этого вывода awk
подсчитывается использование диска записями, число ссылок которых равно 1, а также индексными дескрипторами, которые он видел <link-count>
раз (, т. е. теми, чьи все жесткие ссылки находятся в текущий каталог и, таким образом, как и те, у которых количество ссылок -равно единице, их пространство будет восстановлено после удаления дерева каталогов ).
Вы также можете использовать 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
(, если они не все находятся в одной и той же файловой системе, это будет означать, что у вас будет точка монтирования, которую вы все равно не сможете удалить ).
С тех пор, как я написал этот ответ, Стефан Шазела убедил меня, что его ответ всегда был правильным. Я оставляю свой ответ с кодом, потому что он тоже хорошо работает и обеспечивает красивую -печать. Его вывод выглядит следующим образом:
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 )— хотя я учился у них обоих — я создал свой собственный инструмент и сейчас публикуя его здесь.
Подобно ответу Stéphane Chazelas , он использует find
для получения списка инодов и связанных размеров файлов/каталогов, , но не полагается на «не более одной ссылки "эвристика. Вместо этого он создает список уникальных инодов (, а не файлов/каталогов! )для каждого входного каталога отфильтровывает иноды из других каталогов и суммирует оставшиеся размеры инодов. Таким образом, он учитывает возможные жесткие ссылки в каждом входном каталоге. В качестве побочного эффекта он игнорирует возможные жесткие ссылки из-за пределов набора входных каталогов.
bash -используемые внешние инструменты :find
, xargs
, mktemp
, sort
, tput
, awk
, tr
, numfmt
, touch
, cat
, comm
, rm
. Я знаю, не совсем легкий, но он делает именно то, что я хочу. Я делюсь им здесь, если у кого-то еще есть подобные потребности.
Если что-то можно сделать более эффективно или надежно, комментарии приветствуются! Я кто угодно, только не мастер баша.
Чтобы использовать его, сохраните следующий код в файл сценария 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"
Если ваши имена файлов не содержат символов шаблона или новой строки, вы можете использовать функцию исключения find
+ du
, чтобы сделать это:
find -links +1 -type f \
| cut -d/ -f2- \
| du --exclude-from=- -s *
Бит find
получает все файлы(-type f
)с количеством жестких ссылок больше 1(-links +1
). cut
обрезает ведущие распечатки ./
. Затем du
запрашивается использование диска для каждого каталога, исключая все файлы с несколькими ссылками. Конечно, после удаления моментального снимка теперь могут быть файлы только с одной ссылкой, которых раньше было две, поэтому каждые несколько удалений вам действительно следует -запускать их заново.
Если необходимо работать с произвольными именами файлов, потребуются дополнительные сценарии для заменыdu
(шаблонов оболочки, поэтому экранирование невозможно ).
Кроме того, как указывает Стефан Шазеля, если внутри одного снимка есть жесткие ссылки (, все имена файлов находятся в одном снимке, а не жесткие ссылки между снимками ), эти файлы будут исключены из общего количества. (даже несмотря на то, что удаление моментального снимка восстановит это пространство ).