Отчет о количестве файлов в подкаталогах, Bash

Однострочный

cp $(find a -name "*.jpg" -o -name "*.png") b
5
13.02.2019, 18:45
3 ответа

Я не знаком с Gitbash в Windows, но предполагаю, что на какой бы платформе вы ни запускали этот скрипт, они у вас установлены:

  • bashv4.x или выше (пользователям macOS потребуется установить более новую версию через Homebrew или что-то подобное)
  • GNUfind--на самом деле подойдет любой стандартный Unix find, только не MS -версия для DOS/Windows (, которая больше похожа наgrep)

Если исходить из вышеизложенного, этот скрипт должен помочь:

#!/bin/bash
# USAGE: count_files <dir>...

declare -A filecount

# Tell bash to execute the last pipeline element in this shell, not a subshell
shopt -s lastpipe

# Run through all the user-supplied directories at one go
for d in "$@"; do
  find "$d" -type f | while read f; do
    [[ $f =~ ^(${d%%/}/[^/]+)/ ]] && (( filecount["${BASH_REMATCH[1]}"]++ ))
  done
done

# REPORT!
for k in "${!filecount[@]}"; do
  echo "$k: ${filecount[$k]}"
done
1
27.01.2020, 20:40
#!/bin/bash

shopt -s dotglob nullglob

topdir='./Dir1'

for subdir in "$topdir"/*/; do
    find "$subdir" -type f -exec echo. \; |
    printf '%s: %d\n' "${subdir%/}" "$( wc -l )"
done

Этот небольшой bashскрипт выводит список путей к подкаталогам $topdir, за которым следует количество обычных файлов, найденных (в любом месте )в каждом из этих подкаталогов.

Сценарий перебирает все подкаталоги $topdirи для каждого выполняет команду find

find "$subdir" -type f -exec echo. \;

Это выводит точку на пустой строке для каждого найденного обычного файла в $subdir. Мы выводим точку, потому что их легко посчитать (имена файлов могут содержать символы новой строки ).

Точки передаются в

printf '%s: %d\n' "${subdir%/}" "$( wc -l )"

Здесь printfиспользуется для форматирования вывода. Он принимает путь к подкаталогу (с удаленной последней косой чертой )и количеством файлов.

Счетчик файлов берется из wc -l, который будет подсчитывать точки, поступающие по конвейеру из find(, строго говоря, он подсчитывает не точки, а символы новой строки ). Поскольку сам printfне читает свой стандартный входной поток, вместо этого используется wc -l.

Установка параметров оболочки nullglobи dotglobв начале позволяет нам пропустить весь цикл, если нет подкаталогов в$topdirnullglob), а также включить скрытые имена каталогов в $topdir(, которые сdotglob).

Путем изменения

topdir='./Dir1'

в

topdir=$1

вы можете заставить сценарий принимать путь к каталогу в качестве единственного аргумента командной строки.

Вы можете радикально ускорить find, изменив его на несколько более сложный

find "$subdir" -type f -exec sh -c 'for pathname do echo.; done' sh {} +

(Остальную часть цикла следует оставить как есть ). Это запускает очень маленький сценарий оболочки в строке -для пакетов найденных файлов вместо echoдля каждого файла.Это было бы гораздо быстрее, если предположить, что echoявляется встроенной -командой в оболочке sh. (Вы можете изменить sh -cна bash -c, чтобы убедиться в этом. )Когда используется -exec echo. \;, findбудет выполнять /bin/echo, что будет медленно для каждого файла.

2
27.01.2020, 20:40
find $DIR -mindepth 2 -type f -exec bash -c 'echo ${0%${0#$1/*/}}' {} $DIR  \; | uniq -c
  1. -mindepth 2означает, что мы смотрим только на файлы, которые являются потомками прямых подкаталогов $DIR.
  2. -type fсмотрит только на файлы.
  3. -exec bash -c "..." {} $DIRвыполняет строку с аргументами {}и $DIR, где {}заменяется каждым именем файла, найденным с помощью find.
  4. Часть echoизвлекает соответствующий прямой подкаталог $DIRиз имени файла-потомка. См.https://stackoverflow.com/questions/16623835/remove-a-fixed-prefix-suffix-from-a-string-in-bashдля объяснения того, что делают %и #. 0и 1соответствуют первому и второму аргументам после строки соответственно.
  5. findперечислит всех потомков прямых подкаталогов $DIRпоследовательно, поэтому uniq -cвернет общее количество файлов-потомков вместе с именем для каждого прямого подкаталога.
0
27.01.2020, 20:40

Теги

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