Как заставить команду find распечатать размер файла с именем файла?

107

Если я введу команду поиска следующим образом:

$ find . -name *.ear

Он распечатывает:

./dir1/dir2/earFile1.ear
./dir1/dir2/earFile2.ear
./dir1/dir3/earFile1.ear

Я хочу «напечатать» в командной строке имя и размер:

./dir1/dir2/earFile1.ear  5000 KB
./dir1/dir2/earFile2.ear  5400 KB
./dir1/dir3/earFile1.ear  5400 KB
Брайан Харт
источник

Ответы:

110
find . -name '*.ear' -exec ls -lh {} \;

только h extra из ответа jer.drab.org. экономит время, мысленно конвертируя в МБ;)

Шьям
источник
8
Эта версия будет запускать процесс «ls» для каждого файла. Если у вас много файлов (скажем, более тысячи), лучше оптимизировать их: find . -name '*.ear' -exec ls -lh {} + \;(расширение GNU) или find . -name '*.ear' -print0 | xargs -0 ls -lh. Также вы можете добавить, -type fесли вас интересуют только файлы (или добавить -dв ls, если вы хотите, чтобы сами каталоги были включены без их содержимого).
ash108
2
Ваш ответ не исключает каталоги, поэтому в конечном итоге вы также запустите команду ls для каталогов, что явно неверно.
Faheem Mitha
2
Это действительно неэффективный способ решения задач - и, к сожалению, комментарии ash108 также не идеальны. Для поиска лучше использовать параметр -printf.
oskarpearson
Ответ dmazzoni намного эффективнее, потому что он избегает fork + exec для каждого файла (в 100 раз быстрее на моей машине). Мне пришлось сменить% k на% s. @FaheemMitha: вы можете добавить такие параметры, как -type fподсчет только обычных файлов.
Mr Fooz
@FaheemMitha простое решение find . -name "*.ear" -type fдля файлов. -type dработает для справочников.
anon58192932
112

Вам нужно использовать -exec или -printf. Printf работает так:

find . -name *.ear -printf "%p %k KB\n"

-exec более мощный и позволяет выполнять произвольные команды, поэтому вы можете использовать версию ls или wc для распечатки имени файла вместе с другой информацией. 'man find' покажет вам доступные аргументы printf, которые могут намного больше, чем просто размер файла.

[edit] -printf не входит в официальный стандарт POSIX, поэтому проверьте, поддерживается ли он в вашей версии. Однако большинство современных систем будут использовать GNU find или аналогичную расширенную версию, так что есть большая вероятность, что она будет реализована.

Ли Колдуэлл
источник
Похоже, ваш пример более точен, но я не могу заставить этот пример работать на Solaris 10.
Брайан
Боюсь, что Solaris find вообще не поддерживает -printf: jrwren.wrenfam.com/blog/2006/10/07/solaris-find-sucks cs.bgu.ac.il/~arik/usail/man/solaris/ find.1.html Вы можете установить GNU find, если вас это беспокоит, иначе вам нужно использовать exec или | как было предложено другими.
Ли Колдуэлл,
1
+1 Вроде чище. Чтобы отформатировать вывод, я бы предпочел добавить columnкоманду. find . -name *.ear -printf "%p %k KB\n" | column -t
Amol
1
Этот ответ - гораздо более правильный способ сделать это, чем принятый ответ
угрожающе
2
Эта -printfопция также не работает в OS X. См. Stackoverflow.com/questions/752818/… .
abeboparebop 07
33

простое решение - использовать параметр -ls в find:

find . -name \*.ear -ls

Это дает вам каждую запись в обычном формате "ls -l". Или, чтобы получить конкретный результат, который вы, кажется, ищете, это:

find . -name \*.ear -printf "%p\t%k KB\n"

Это даст вам имя файла, за которым следует размер в КБ.

Майкл Крамер
источник
Даже не знал о lsварианте, он должен быть намного выше в списке ответов, чем он есть.
Прометей
24

Используя gnu find, я думаю, это то, что вам нужно. Он находит все реальные файлы, а не каталоги (-тип f), и для каждого печатает имя файла (% p), табуляцию (\ t), размер в килобайтах (% k), суффикс «KB», а затем перевод строки (\ n).

find . -type f -printf '%p\t%k KB\n'

Если команда printf не форматирует вещи так, как вы хотите, вы можете использовать exec, а затем команду, которую вы хотите выполнить для каждого файла. Используйте {} в качестве имени файла и завершите команду точкой с запятой (;). В большинстве оболочек все три этих символа должны быть экранированы обратной косой чертой.

Вот простое решение, которое находит и распечатывает их с помощью "ls -lh", который покажет вам размер в удобочитаемой форме (k для килобайт, M для мегабайт):

find . -type f -exec ls -lh \{\} \;

В качестве еще одной альтернативы "wc -c" напечатает количество символов (байтов) в файле:

find . -type f -exec wc -c \{\} \;
Дмаццони
источник
+1 За исключением того, что он пропущен -name '*.ear'в примерах, это должен быть ответ №1. Он точно отвечает на вопрос, объясняет значение синтаксиса и дает несколько альтернатив.
OsakaWebbie
это должен быть принятый ответ, так как он не запускает новую команду для каждой строки, поэтому он намного быстрее, чем принятый в настоящее время ответ от shyam
jirislav
В самом деле, это должен быть правильный ответ. Кроме того, find . -type f -printf '%k KB\t %p\n'то есть сначала распечатать размер файла, скорее всего, будет лучше с точки зрения форматирования из-за выравнивания.
myradio
8
find . -name '*.ear' -exec du -h {} \;

Это дает вам только размер файла вместо всего ненужного.

2121791
источник
wcработает для этого лучше, если вам нужен размер в байтах.
Alex
4

Awk может исправить вывод, чтобы дать именно то, о чем спрашивал спрашивающий. В моей системе Solaris 10 команда find -ls выводит размер в КБ во втором поле, поэтому:

% find . -name '*.ear' -ls | awk '{print $2, $11}'
5400 ./dir1/dir2/earFile2.ear
5400 ./dir1/dir2/earFile3.ear
5400 ./dir1/dir2/earFile1.ear

В противном случае используйте -exec ls -lh и выберите поле размера из вывода. Снова в Solaris 10:

% find . -name '*.ear' -exec ls -lh {} \; | awk '{print $5, $9}'
5.3M ./dir1/dir2/earFile2.ear
5.3M ./dir1/dir2/earFile3.ear
5.3M ./dir1/dir2/earFile1.ear
tpgould
источник
4

Почему бы не использовать ду-а ? Например

find . -name "*.ear" -exec du -a {} \;

Работает на Mac

сиещие
источник
3

Я боролся с этим в Mac OS X, где команда find не поддерживает -printf.

Решение, которое я нашел, которое, по общему признанию, полагается на «группу» для всех файлов, являющихся «персоналом», было ...

ls -l -R | sed 's/\(.*\)staff *\([0-9]*\)..............\(.*\)/\2 \3/'

Это разбивает вывод ls long на три токена

  1. материал перед текстом "персонал"
  2. размер файла
  3. имя файла

Затем выводятся токены 2 и 3, т.е. вывод - это количество байтов, а затем имя файла

8071 sections.php
54681 services.php
37961 style.css
13260 thumb.php
70951 workshops.php
Майк М
источник
1
Полезно знать .. Версия GNU findдоступна через homebrew сbrew install findutils
mwfearnley
2

Это должно дать вам то, что вы ищете, включая форматирование (т.е. сначала имя файла, а затем размер):

find . -type f -iname "*.ear" -exec du -ah {} \; | awk '{print $2"\t", $1}'

пример вывода (где я раньше -iname "*.php"получал какой-то результат):

./plugins/bat/class.bat.inc.php  20K
./plugins/quotas/class.quotas.inc.php    8.0K
./plugins/dmraid/class.dmraid.inc.php    8.0K
./plugins/updatenotifier/class.updatenotifier.inc.php    4.0K
./index.php      4.0K
./config.php     12K
./includes/mb/class.hwsensors.inc.php    8.0K
Адриано72
источник
2

Попробуйте следующие команды:

GNU stat:

find . -type f -name *.ear -exec stat -c "%n %s" {} ';'

BSD stat:

find . -type f -name *.ear -exec stat -f "%N %z" {} ';'

однако statне является стандартным, так duи wcможет быть лучшим подходом:

find . -type f -name *.ear -exec sh -c 'echo "{} $(wc -c < {})"' ';'
Kenorb
источник
1

Вы можете попробовать это:

find. -name *.ear -exec du {} \;

Это даст вам размер в байтах. Но команда du также принимает параметры -k для КБ и -m для МБ. Это даст вам результат вроде

5000  ./dir1/dir2/earFile1.ear
5400  ./dir1/dir2/earFile2.ear
5400  ./dir1/dir3/earFile1.ear
Яба
источник
0
find . -name "*.ear" -exec ls -l {} \;
Джереми Уэзерс
источник
0

Если вам нужно получить общий размер, вот предложение сценария

#!/bin/bash
totalSize=0

allSizes=`find . -type f -name *.ear -exec stat -c "%s" {} \;`

for fileSize in $allSizes; do
    totalSize=`echo "$(($totalSize+$fileSize))"`
done
echo "Total size is $totalSize bytes"
Дэмиен С
источник