Подтвердить что ты не робот

Дисковое использование файлов, имена которых соответствуют регулярному выражению, в Linux?

Итак, во многих ситуациях мне нужен способ узнать, сколько из моего дискового пространства используется тем, что я знаю, что нужно избавиться, конвертировать в другой формат, хранить в другом месте (например, DVD-диски с данными), переходить на другой раздел и т.д. В этом случае я просматриваю раздел Windows с загрузочного носителя SliTaz Linux.

В большинстве случаев я хочу размер файлов и папок, и для этого я использую ncdu на основе NCurses:

                ncdu

Но в этом случае я хочу, чтобы получить размер всех файлов, соответствующих регулярному выражению. Пример regex для .bak файлов:

.*\.bak$

Как получить эту информацию, учитывая стандартный Linux с основными утилитами GNU или BusyBox?

Изменить:. Вывод предназначен для синтаксического анализа с помощью script.

4b9b3361

Ответ 1

Я предлагаю что-то вроде: find . -regex '.*\.bak' -print0 | du --files0-from=- -ch | tail -1

Некоторые примечания:

  • Параметр -print0 для find и --files0-from для du существует, чтобы избежать проблем с пробелами в именах файлов
  • Регулярное выражение сопоставляется с целым путем, например. ./dir1/subdir2/file.bak, а не только file.bak, поэтому, если вы его измените, учтите это
  • Я использовал флаг h для создания "удобочитаемого" формата, но если вы хотите проанализировать вывод, вам может быть лучше с k (всегда используйте килобайты)
  • Если вы удалите команду tail, вы также увидите размеры конкретных файлов и каталогов

Sidenote: хороший инструмент GUI для определения того, кто ел ваше дисковое пространство, FileLight. Он не выполняет регулярных выражений, но очень удобен для поиска больших каталогов или файлов, засоряющих ваш диск.

Ответ 2

du - мой любимый ответ. Если у вас есть фиксированная структура файловой системы, вы можете использовать:

du -hc *.bak

Если вам нужно добавить поддиры, просто добавьте:

du -hc *.bak **/*.bak **/**/*.bak

и т.д.

Однако это не очень полезная команда, поэтому используйте вашу находку:

TOTAL=0;for I in $(find . -name \*.bak); do  TOTAL=$((TOTAL+$(du $I | awk '{print $1}'))); done; echo $TOTAL

Это будет отражать общий размер в байтах всех файлов, которые вы найдете.

Надеюсь, что это поможет.

Ответ 3

Запустите это в оболочке Bourne, чтобы объявить функцию, которая вычисляет сумму размеров всех файлов, соответствующих шаблону регулярного выражения в текущем каталоге:

sizeofregex() { IFS=$'\n'; for x in $(find . -regex "$1" 2> /dev/null); do du -sk "$x" | cut -f1; done | awk '{s+=$1} END {print s}' | sed 's/^$/0/'; unset IFS; }

(В качестве альтернативы вы можете поместить его в script.)

Применение:

cd /where/to/look
sizeofregex 'myregex'

В результате будет число (в KiB), в том числе 0 (если нет файлов, соответствующих вашему регулярному выражению).

Если вы не хотите, чтобы он смотрел в других файловых системах (скажем, вы хотите искать все .so файлы под /, который является mount /dev/sda1, но не под /home, который является mount /dev/sdb1, добавьте параметр -xdev в find в приведенной выше функции.

Ответ 4

Предыдущие решения не работали правильно для меня (у меня была проблема с трубопроводом du), но следующее отлично работало:

find path/to/directory -iregex ".*\.bak$" -exec du -csh '{}' + | tail -1

Параметр iregex - это нечувствительное к регистру регулярное выражение. Используйте regex, если вы хотите, чтобы он был чувствительным к регистру.

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

find path/to/directory -iname "*.bak" -exec du -csh '{}' + | tail -1

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

find path/to/directory -iname "*.bak" -exec du -csh '{}' +

Эти подходы позволяют избежать проблемы с подкаталогом в ответе @MaddHackers.

Надеемся, что это поможет другим в той же ситуации (в моем случае, найти размер всей DLL в .NET-решении).

Ответ 5

Если у вас все в порядке с шаблонами glob, и вас интересует только текущий каталог:

stat -c "%s" *.bak | awk '{sum += $1} END {print sum}'

или

sum=0
while read size; do (( sum += size )); done < <(stat -c "%s" *.bak)
echo $sum

Директива %s stat указывает байты, а не килобайты.

Если вы хотите спуститься в подкаталоги, с bash версией 4, вы можете shopt -s globstar и использовать шаблон **/*.bak

Ответ 6

В принятом ответе предлагается использовать

find . -regex '.*\.bak' -print0 | du --files0-from=- -ch | tail -1

но это не работает в моей системе, так как du не знает опции --files-0-from в моей системе. Только GNU du знает эту опцию, она не является частью POSIX Standard (так что вы не найдете ее во FreeBSD или macOS) и вы не найдете его на Linux-системах на базе BusyBox (например, большинство встроенных систем Linux) или любой другой Linux-системе, которая не использует GNU du версия.

Затем появляется ответ, предлагающий использовать:

find path/to/directory -iregex .*\.bak$ -exec du -csh '{}' + | tail -1

Это решение будет работать до тех пор, пока не будет найдено слишком много файлов, поскольку + означает, что find будет пытаться вызвать du с таким количеством ударов, сколько возможно в одном вызове, однако может быть максимальное количество аргументов (N), поддерживаемых системой, и если их больше, чем это значение, find будет вызывать du несколько раз, разбивая хиты на группы, меньшие или равные N элементам, каждый и в этом случае результат будет неправильным и отобразит только размер последнего вызова du.

Наконец, есть ответ с использованием stat и awk, что является хорошим способом сделать это, но он полагается на чередование оболочки таким образом, что поддерживается только Bash 4.x или новее. Он не будет работать со старыми версиями, и если он работает с другими оболочками, это непредсказуемо.

Решение, совместимое с POSIX (работает с Linux, macOS и любыми вариантами BSD), которое не страдает никакими ограничениями и что, безусловно, будет работать с каждой оболочкой:

find . -regex '.*\.bak' -exec stat -f "%z" {} \; | awk '{s += $1} END {print s}'