Дисковое использование файлов, имена которых соответствуют регулярному выражению, в Linux?
Итак, во многих ситуациях мне нужен способ узнать, сколько из моего дискового пространства используется тем, что я знаю, что нужно избавиться, конвертировать в другой формат, хранить в другом месте (например, DVD-диски с данными), переходить на другой раздел и т.д. В этом случае я просматриваю раздел Windows с загрузочного носителя SliTaz Linux.
В большинстве случаев я хочу размер файлов и папок, и для этого я использую ncdu на основе NCurses:
![ncdu]()
Но в этом случае я хочу, чтобы получить размер всех файлов, соответствующих регулярному выражению. Пример regex для .bak файлов:
.*\.bak$
Как получить эту информацию, учитывая стандартный Linux с основными утилитами GNU или BusyBox?
Изменить:. Вывод предназначен для синтаксического анализа с помощью script.
Ответы
Ответ 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}'