Как `du` только пространство, используемое файлами, которые не связаны жесткими ссылками в другом месте?


14

Используя rsync --link-destдля экономии места снимки , как я могу выяснить, сколько места я фактически сэкономил? Или более общий:

Как выяснить , сколько места каталога использует рассматривать только файлы, которые не hardlinked в другом месте за пределами структуры каталогов? По-разному спрашивается: сколько места будет на самом деле освобождено после удаления этого каталога? ( du -hsбудет лежать. Может быть включено пространство, необходимое для самих жестких ссылок)


2
По умолчанию GNU duсчитает размеры файлов только один раз, даже если они жестко связаны, если вы не используете параметр -l/ --count-links. Вы запускаете duвсе дерево дважды с этой опцией и без нее, и разница между размерами должна заключаться в том, сколько места вы сэкономили во всех каталогах.
— jw013

Ответы:


9

Предполагая, что нет внутренних жестких ссылок (то есть каждый файл с более чем одной жесткой ссылкой связан вне дерева), вы можете сделать:

find . -links -2 -print0 | du -c --files0-from=-

РЕДАКТИРОВАТЬ И вот что я набросал в комментарии, применил. Только без du; Слава @StephaneChazelas для замечаний duне нужна. Объяснение в конце.

( find . -type d -printf '%k + ' ; \
  find . \! -type d -printf '%n\t%i\t%k\n' | \
    sort | uniq -c                         | \
    awk '$1 >= $2 { print $4 " +\\" }' ; \
  echo 0 ) | bc

Что мы делаем, это создаем строку с использованием диска (в КБ) каждого соответствующего файла, разделенных знаком плюс. Затем мы кормим это большое дополнение к bc.

Первый find вызов делает это для каталогов.

Второй findвыводит количество ссылок, индекс и использование диска. Мы передаем этот список черезsort | uniq -c чтобы получить список (количество появлений в дереве, количество ссылок, индекс, использование диска).

Мы передаем этот список черезawk , и, если первое поле (количество появлений) больше или равно второму (количество жестких ссылок), то есть нет ссылок на этот файл извне дерева, выведите четвертое поле ( использование диска) со знаком плюс и обратной косой чертой.

Наконец, мы выводим a 0, поэтому формула синтаксически верна (в +противном случае это будет en ) и передаем ееbc . Уф.

(Но я бы использовал более простой первый метод, если он дает достаточно хороший ответ.)


Спасибо, да, если это требование выполнено, оно работает. Но что, если это не так?
— Тобиас Кинцлер

Это не работает, так как не учитывает размер самих каталогов (которые обычно имеют по крайней мере 2 ссылки, а если бы их не было, файлы были бы подсчитаны дважды).
— Стефан Шазелас

1
Тогда необходимо будет использовать findдля печати список всех файлов с их инодами и количеством ссылок; затем некоторая комбинация, sort | uniq -cчтобы узнать, сколько раз каждый инод появляется в дереве, затем отфильтровать те, у которых число ссылок превышает количество появлений ... и затем передать этот список du. Но если требование выполнено, лучше сэкономить.
— Ангус

@StephaneChazelas Это работает, но это правда, что он не учитывает собственный размер каталогов. Если бы только duбыл -dпараметр, похожий на ls's ...
— angus

Также обратите внимание, что в btrfsфайловых системах количество ссылок на каталоги всегда 1, поэтому вам нужно добавить! -type d
— Стефан Шазелас

5

По сути, вам нужно получить номера инодов и количество ссылок для всех файлов (не-каталогов), сравнить это количество ссылок с количеством вхождений каждого инода и, если они различаются, исключить файл.

Предполагая, что они все в одной файловой системе, что-то вроде этого должно работать (с GNU find):

find . -type d -printf '%k\n' -o -printf '%i %n %k\n' |
   awk '
     NF==1{t+=$0; next}
     {n1[$1]=$2; n2[$1]++; s[$1]=$3}
     END {
       for (i in n1)
         if (n1[i] == n2[i])
           t+=s[i]
       print t
     }'

Да, что я сказал (спасибо за кредит). Но дополнительную точность, которую вы получаете, считая каталоги, вы теряете, добавляя неточное использование диска.
— Ангус

@angus, что вы подразумеваете под "неточным использованием диска"?
— Стефан Шазелас

Ничего, я полностью ошибся в том, что %kсообщил. Это здорово, duсовсем не нужно! Я обновлю свой ответ, когда вернусь домой. Благодарность!
— Ангус

3

du фактически не будет лгать;) Он анализирует каталог, который ему дается, считая только первые из всех жестких ссылок, указывающих на тот же инод, с которым он сталкивается.

Если вы спросите, duчто он видит только в одном каталоге, ему все равно, что есть другие жесткие ссылки, указывающие на то же содержимое:

$ du -h daily.0 && du -hc daily.1
29G /daily.0
29G /daily.1

Теперь поместите его в одну и ту же строку (начиная с самой последней для инкрементных резервных копий rsync с --link-dest):

$ du -hc daily.0 daily.1
29G /daily.0
364M /daily.1
29G total

Или весь резервный каталог:

$ du -hc --max-depth=1 /snapshots
29G /daily.0
364M /daily.1
537M /daily.2
333M /daily.3
30G total

Любой файл в 'daily.1', ссылающийся на inode (он же "настоящий" файл), уже указанный в "daily.0", не будет засчитан.

Поэтому удаление daily.1 сэкономит 364 МБ на вашем устройстве.

УДАЛЯТЬ

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.