Как `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.