Я не знаком с Gitbash в Windows, но предполагаю, что на какой бы платформе вы ни запускали этот скрипт, они у вас установлены:
bash
v4.x или выше (пользователям macOS потребуется установить более новую версию через Homebrew или что-то подобное)find
--на самом деле подойдет любой стандартный 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
#!/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
в начале позволяет нам пропустить весь цикл, если нет подкаталогов в$topdir
(с nullglob
), а также включить скрытые имена каталогов в $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
, что будет медленно для каждого файла.
find $DIR -mindepth 2 -type f -exec bash -c 'echo ${0%${0#$1/*/}}' {} $DIR \; | uniq -c
-mindepth 2
означает, что мы смотрим только на файлы, которые являются потомками прямых подкаталогов $DIR
. -type f
смотрит только на файлы. -exec bash -c "..." {} $DIR
выполняет строку с аргументами {}
и $DIR
, где {}
заменяется каждым именем файла, найденным с помощью find
. echo
извлекает соответствующий прямой подкаталог $DIR
из имени файла-потомка. См.https://stackoverflow.com/questions/16623835/remove-a-fixed-prefix-suffix-from-a-string-in-bashдля объяснения того, что делают %
и #
. 0
и 1
соответствуют первому и второму аргументам после строки соответственно. find
перечислит всех потомков прямых подкаталогов $DIR
последовательно, поэтому uniq -c
вернет общее количество файлов-потомков вместе с именем для каждого прямого подкаталога.