Мне нужен скрипт, который подсчитывает файлы в каталоге (и подкаталогах). Я взял следующий скрипт и изменил его под свои нужды.
Работает как надо, за исключением папок с пробелами. Я почти уверен, что где-то не хватает кавычек, но пока не могу разобраться.
Дополнительная информация
- Linux 2.6.22.19-0.4-default (этот сервер больше не находится в продуктивной среде.)
- GNU find версия 4.2.31
- Я не могу переименовать каталоги.
Пример структуры каталога
.
..
01_infos
02_sent
03_inbox
04_public and private
197.
145.
329.
13.
Сценарий
#!/bin/bash
# Write a script that will count the number of files in each of your subdirectories.
# -------------------------------------------------------------------------
# Copyright (c) 2001 nixCraft project <http://cyberciti.biz/fb/>
# This script is licensed under GNU GPL version 2.0 or above
# -------------------------------------------------------------------------
# This script is part of nixCraft shell script collection (NSSC)
# Visit http://bash.cyberciti.biz/ for more information.
# -------------------------------------------------------------------------
START=$HOME
# change your directory to command line if passed
# otherwise use home directory
[ $# -eq 1 ] && START=$1 || :
if [ ! -d $START ]
then
echo "$START not a directory!"
exit 1
fi
# use find command to get all subdirs name in DIRS variable
DIRS=$(find "$START" -type d)
# loop thought each dir to get the number of files in each of subdir
for d in $DIRS
do
echo "$d directory has $(find "$d" -maxdepth 1 -regex '.*\.' -type f | wc -l) files" || :
done
выход
./01_infos directory has 1 files
./02_sent directory has 9 files
./03_inbox has 4 files
find: ./04_public: No such file or directory
решение1
У вас не хватает двойных кавычек (всегда заключайте подстановки переменных $foo
и подстановки команд в двойные кавычки$(foo)
, если только вы не знаете, почему вы можете безопасно их отключить, а почему вам нужно их отключить). Но это еще не вся проблема.
if [ ! -d $START ]
должно быть if [ ! -d "$START" ]
.
DIRS=$(find "$START" -type d)
На этом этапе DIRS
содержит имя начального каталога и его подкаталогов рекурсивно, с символами новой строки между ними. Так что если у вас есть имя каталога, содержащее символ новой строки, вы проиграли: невозможно узнать, какие символы новой строки пришли из имени каталога, а какие были разделителями. Если вы знаете, что в именах файлов нет символов новой строки, вы можете проанализировать вывод find
, но как вы узнаете?
Кстати, здесь можно не использовать двойные кавычки, $(…)
потому что это присваивание переменных, а подстановки в присваиваниях неявно защищены. Однако, обратите внимание, что не защищено подобным образом. Лучше использовать кавычки, если вы не владеете языком скриптов оболочки, как и все люди, которые будут поддерживать ваш скрипт.export DIRS=$(…)
for d in $DIRS
Вот где вы проигрываете: вы хотите разбить $DIRS
на слова, поэтому вы не можете поставить двойные кавычки, но они вам нужны, потому что $DIRS
все элементы будут объединены вместе, а имена файлов внутри пробелов будут разделителями, если вы оставите их без кавычек.
Обычно, когда вы используете find
, вы должны заставить его вызвать команду обработки с -exec
опцией. Если у вас нет жесткого контроля над именами файлов, не анализируйте вывод find
: он неоднозначен.
find "$START" -type d -exec sh -c '
echo "$0 directory has $(find "$0" -maxdepth 1 -regex ".*\\." -type f -printf \\n | wc -l) files whose name ends with ."
' {} \;
Обратите внимание еще раз на то, что во встроенной find
команде при анализе выходных данных find
ваш подсчет будет неверным, если какое-либо имя файла содержит символ новой строки.
решение2
А как насчет этого?
find . -type d -exec sh -c '/bin/echo -n "{}"; find "{}" -maxdepth 1 -regex ".*\." -type f | wc -l; ' \;
Вывод не такой приторный, но он не требует скрипта и работает для каталогов с пробелами, а также другими небуквенно-цифровыми символами.
решение3
У вас классическая ошибка кавычек. Исправьте цикл for так, чтобы он выглядел так:
for d in "$DIRS"
В качестве альтернативы вы можете find
напрямую передать его вывод, например:
find "$START" -type d | while read d
do # and so on...
Кстати, этот || :
бит совершенно избыточен, поскольку echo
всегда имеет возвращаемое значение 0.