Как рассчитать рекурсивно для количества файлов в нескольких каталогах?

Смотрите на -C опция к tcpdump:

   -C     Before  writing  a  raw  packet  to  a savefile, check whether 
 the file is currently larger than file_size and, if so, close the current 
 savefile and open a new one.  Savefiles after the  first savefile  will  have 
 the name specified with the -w flag, with a number after it, starting at 1 
 and continuing upward. The units of file_size are  millions  of  bytes 
 1,000,000  bytes, not 1,048,576 bytes).

Если Вы устанавливаете флаг размера на что-то довольно маленькое и пишете a cron сценарий, который тестирует на существование новых водосливных файлов каждую минуту или так, затем загружает переполненные файлы через FTP и меняет имя прежде, чем удалить их, необходимо получить то, что Вы ищете.

Эта установка все еще была бы уязвима для DOS, если что-то лавинно рассылает ссылку быстрее, чем Ваш сценарий крона может загрузить новые файлы, и если у Вас есть возможность SSH вообще, я настоятельно рекомендую ssh конвейерно обработайте обманывают @Chris предложения Green выше.

4
03.04.2013, 12:22
5 ответов

GNU (bash, wc и find) решение, которое работает с любым путем, даже те, которые содержат пробелы, новые строки или запускаются с тире:

shopt -s nullglob
for dir in ./*/
do
    printf '%s\n' "$dir"
    find "$dir" -mindepth 1 -printf x | wc --chars
done

Объяснение:

  • nullglob опция предотвращает ошибки если ./ не содержит каталогов.
  • ./ в каталоге шарик гарантирует что имена файлов, запускающиеся с тире ("-"), не испортит echo или find.
  • Наклонная черта в конце шарика гарантирует, что только каталоги обрабатываются.
  • -mindepth 1 старается не считать сам каталог.
  • Если Вы хотите включать каталоги, которые запускаются с точки на верхнем уровне, необходимо работать shopt -s dotglob перед for цикл.
6
27.01.2020, 20:50
  • 1
    Работы как очарование. Спасибо за Ваш ответ и Ваши объяснения. –  Majiy 03.04.2013, 12:58
  • 2
    +1 для -printf x : иначе значение по умолчанию произведет название файла (который мог: содержите "новую строку", и поэтому считаться дважды. Или содержите другие вещи, такие как символы "NULL", делая много дросселя команд), –  Olivier Dulac 03.04.2013, 14:35
  • 3
    @OlivierDulac путь не может содержать нулевые символы. Это - на самом деле единственный символ, который они не могут содержать. –  l0b0 03.04.2013, 14:41
  • 4
    @l0b0: положительная сторона (я должен был знать, поскольку я использую "-print0" и то же с xargs, когда доступный). Но тем не менее, хороший избежать каких-либо "странных" символов там ^^ (новая строка, по крайней мере) –  Olivier Dulac 03.04.2013, 14:49

Вот другой метод с bash4 +. Обратите внимание, что это следует за символьными ссылками и не включает . и .. в отличие от ответа l0b0 (который может или не может быть тем, что Вы хотите):

(
    shopt -s dotglob globstar nullglob
    for dir in */; do
        set -- "$dir"/**/*
        printf '%s: %d\n' "$dir" "$#"
    done
)
1
27.01.2020, 20:50
  • 1
    , который я не использую "/**" (недостаточно мобильности): но это считает файл, запускающийся с "."? (исключая: .bashrc, и т.д.), –  Olivier Dulac 03.04.2013, 14:37
  • 2
    @OlivierDulac - Это dotglob, который включен наверху. –  Chris Down 03.04.2013, 14:47
  • 3
    хорошо, я никогда не использую его (не доступный прямо сейчас для меня) ^^, но интересно, соответствовал ли "/**", все, но "/**/*" конкретно ограничивают его не-"." subdirs? Исправьте меня, если я неправ –  Olivier Dulac 03.04.2013, 14:52
  • 4
    @OlivierDulac - Как я сказал, dotglob средства управления это. С включенным dotglob это соответствует им. –  Chris Down 03.04.2013, 14:57

$(find -maxdepth 1 -type d) производит список каталогов в текущем каталоге. Если нет каталоги, имя которых начинается с a ., это - сложный способ записать */. Это также ненадежно: это только работает, если ни одни из имен каталогов не содержат пробел или globbing символы \[?*. Поэтому результат замены команды $(…) разделяется на отдельные слова везде, где существует пробельный символ, и каждое слово интерпретируется как шарик (подстановочный шаблон имени файла). Можно избежать этого поведения путем помещения замены команды в двойные кавычки ("$()"), но затем список, на котором выполняет итерации цикл, будет содержать единственный элемент, который является конкатенацией имен каталогов, разделенных новыми строками.

Отметьте это правило программирования оболочки: всегда помещайте двойные кавычки вокруг подстановок переменных и управляйте заменами ("$foo", "$(foo)") если Вы не знаете, что необходимо пропустить двойные кавычки, и Вы понимаете, как безопасно пропустить их.

Другой проблемой с Вашим сценарием является простая: echo find "$dir" всегда распечатывает одну строку; Вы имели в виду find "$dir".

for dir in */; do
  echo "$dir"
  find "$dir" | wc -l
done

Обратите внимание, что это только работает, если никакой файл в том дереве не содержит новые строки. Если они могли бы, можно сделать find управляйте печатают что-то надежное. С GNU находят (т.е. на невстроенном Linux или Cygwin):

for dir in */; do
  echo "$dir"
  find "$dir" -printf a | wc -c
done

Портативно:

for dir in */; do
  echo "$dir"
  find "$dir" -exec printf %c {} + | wc -c
done
1
27.01.2020, 20:50

Маленький, немного более быстрый вариант портативных решений Gilles был бы:

for dir in */; do
  echo "$dir"
  #find "$dir" -exec printf %c {} + | wc -c
  find "$dir" -print0 | tr -dc '\0' | wc -c
done
0
27.01.2020, 20:50

Использование GNU Parallel, он будет выглядеть так:

parallel -0 --tag  'find {} |wc -l' ::: */

Он будет запущен один находку | WC на CPU параллельно. В зависимости от вашей системы хранения параллелизация может увеличить или уменьшить скорость - только способ узнать, чтобы проверить его. Количество процессов можно регулировать с помощью -J .

Parallel GNU - это общий параллельный панель, и позволяет легко запускать задания параллельно на том же машине или на нескольких машинах, к которым у вас есть SSH.

Если у вас есть 32 разные задания, которые вы хотите запустить на 4 процессорах, прямой путь для параллелизма - это управлять 8 рабочими заданиями на каждом ЦП:

Simple scheduling

GNU Parallel вместо этого порождает новый процесс, когда одна отделка - сохранение процессоров активно И, таким образом, экономить время:

GNU Parallel scheduling

Установка

Если GNU Parallel не упакован для вашего распределения, вы можете сделать личную установку, что не требует доступа к корню. Это может быть сделано за 10 секунд, делая это:

(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash

для других вариантов установки см. http://git.savannah.gnu.org/cgit/parallel.git/tree/readme

Узнать больше

Увидеть больше примеров: http://www.gnu.org/software/parallel/man.html

Смотреть видео в Intro: https://www.youtube.com/playlist?List= PL284C9FF2488BC6D1

Прогулка по учебнику: http://www.gnu.org/software/parallel/parallel_tutorial.html

Зарегистрируйтесь в списке электронных напитков, чтобы получить поддержку: HTTPS: // списки .gnu.org / mailman / listinfo / parallel

0
27.01.2020, 20:50

Теги

Похожие вопросы