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

194

У меня есть каталог с большим количеством файлов. Я не вижу lsпереключателя для подсчета. Есть ли какая-то магия командной строки, чтобы получить количество файлов?

Блейк
источник
stackoverflow.com/questions/9157138/…
Тревор Бойд Смит
tree . | tailили tree -a . | tailвключить скрытые файлы / каталоги, treeрекурсивно, если это то, что вы хотите.
CodyChan

Ответы:

240

Используя широкое определение «файла»

ls | wc -l

(обратите внимание, что он не считает скрытые файлы и предполагает, что имена файлов не содержат символов новой строки).

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

find . ! -name . -prune -print | grep -c /

Или рекурсивно:

find .//. ! -name . -print | grep -c //
Джеймс Рот
источник
23
wcпрограмма для подсчета слов -lПереключатель заставляет его считать строки. В этом случае он считает строки в выводе из ls. Так всегда меня учили подсчитывать количество файлов для данного каталога.
Сэнди
20
пожалуйста, добавьте примечание, которое lsимеет место, ls -1если вывод представляет собой трубу.
Lesmana
6
это не все в каталоге - вы пропустили точечные файлы, и соберите еще пару строк. Пустой каталог все равно вернет 1 строку. И если вы позвоните ls -la, вы получите три строки в каталоге. Вы хотите ls -lA | wc -lпропустить .и ..записи. Тем не менее, вы все равно будете в одиночестве.
1
Пустой каталог возвращает 0 для меня
Джеймс Рот
2
Исправленный подход, который бы не двойные счета файлов с символами новой строки в названии, были бы это: ls -q | wc -l- хотя отмечают , что скрытые файлы все еще не будут подсчитаны этим подходом, и что каталоги будут учитываться.
Godlygeek
30

Для узкого определения файла:

 find . -maxdepth 1 -type f | wc -l
Мацей Печотка
источник
И вы, конечно, можете опустить -maxdepth 1рекурсивный подсчет файлов (или настроить его для желаемой максимальной глубины поиска).
user7089
1
Если у вас есть файл, имя которого содержит символ новой строки, этот подход неверно посчитает его дважды.
Godlygeek
7
Исправленный подход, при котором файлы с двойными строками в названии не удваиваются, будет выглядеть так:find -maxdepth 1 -type f -printf "\n" | wc -l
godlygeek
+1 Разрешить скрытые файлы и игнорировать каталоги
Майкл Даррант
14
ls -1 | wc -l

...

$ ls --help | grep -- '  -1'
    -1                         list one file per line

...

$ wc --help | grep -- '  -l'
    -l, --lines            print the newline counts

PS: Примечание ls - <номер-один> | туалет - <буква-л>

nicomen
источник
10
Большинство версий lsделают -1автоматически, когда вывод в трубу.
Деннис Уильямсон
3
@ Денис, это интересно, я не знал, что приложение может сказать, что его вывод идет в трубу.
ксенотеррацид
1
Я + редактировал эту версию, поскольку она более явная. Хотя, да, ls использует -1, если он передан по каналу (попробуйте: ls | cat), я считаю синтаксис -1 более явным.
таращиться
3
@xenoterracide: In Bash:[[ -p /dev/stdin ]] && echo "stdin is from a pipe"
Деннис Уильямсон
2
В моих тестах было также значительно быстрее предоставить опцию -f, чтобы избежать сортировки имен файлов ls. К сожалению, вы все равно получите неправильный ответ, если ваши имена файлов содержат символы новой строки.
Сэмюэль Эдвин Уорд
10

Вероятно, наиболее полный ответ с использованием ls/ wcпары

ls -Aq | wc -l

если вы хотите считать точечные файлы, и

ls -q | wc -l

в противном случае.

  • -Aэто считать точечные файлы, но опустить .и ...
  • -qсделать lsзамену неграфических символов, в частности символа новой строки, с ?выводом 1 строки для каждого файла

Чтобы получить однострочный выход из lsтерминала (т.е. без подключения к нему wc), -1необходимо добавить опцию.

(поведение lsпротестировано с coreutils 8.23)

Frax
источник
2
Как вы сказали, -1не нужно. Что касается «он обрабатывает переносы строк в именах файлов разумно с выводом на консоль» , то это из-за -qпереключателя (который вы должны использовать вместо того, -bпотому что он переносим), который «заставляет записывать каждый экземпляр непечатных символов имени файла и символов <tab> в качестве символа <вопросительный знак> ('?'). Реализации могут предоставлять эту опцию по умолчанию, если вывод осуществляется на терминальное устройство. " Например, ls -Aq | wc -lчтобы подсчитать все файлы / каталоги или ls -qp | grep -c /только не скрытые каталоги и т. Д.
don_crissti
Спасибо за ваш вклад. Изменено -bна -q.
Фракс
7

Если вы знаете, что текущий каталог содержит хотя бы один не скрытый файл:

set -- *; echo "$#"

Это очевидно обобщается на любой шар.

В сценарии это иногда вызывает нежелательный побочный эффект перезаписи позиционных параметров. Вы можете обойти это, используя subshell или с помощью функции (версия Bourne / POSIX), например:

count_words () {
  eval 'shift; '"$1"'=$#'
}
count_words number_of_files *
echo "There are $number_of_files non-dot files in the current directory"

Альтернативное решение есть $(ls -d -- * | wc -l). Если глобус есть *, команда может быть сокращена до $(ls | wc -l). Анализ выходных данных lsвсегда делает меня неловким, но здесь это должно работать до тех пор, пока ваши имена файлов не содержат символов новой строки или вы не можете lsих избежать. И $(ls -d -- * 2>/dev/null | wc -l)имеет преимущество в том, что изящно обрабатывает случай несовпадающего глобуса (т. Е. Возвращает 0 в этом случае, тогда как set *метод требует тщательного тестирования, если глобус может быть пустым).

Если имена файлов могут содержать символы новой строки, альтернативой является использование $(ls -d ./* | grep -c /).

Любое из тех решений, которые полагаются на передачу расширения глобуса, lsможет завершиться ошибкой со слишком длинной ошибкой списка аргументов, если имеется много подходящих файлов.

жилль
источник
1
Вы действительно хотите создать 13 923 позиционных параметра? И вы должны сделать свою локальную переменную localили устранить ее: eval $1=$#или просто использовать echo $#и делать number_of_files=$(count_words *).
Деннис Уильямсон
1
@Dennis: часть цели состояла в том, чтобы избежать разветвления. Я думаю, это не проблема 21-го века. Хорошо, я признаю, что меня больше не волнуют не-POSIX-оболочки, поэтому я мог бы избежать временной переменной.
Жиль
Почему вы вычли один из $#(вы не сделали этого до редактирования)?
Деннис Уильямсон
@Dennis: Я все еще избегаю разветвления (ну, на машинах с медленным процессором, таких как маршрутизаторы) это имеет значение, и я передаю имя переменной как $1. Так что я хочу посчитать количество параметров, которые не являются первым параметром. (Я не могу использовать, shiftпотому что мне нужно держать имя переменной рядом.) (Хмм, теперь, если бы вы спросили о первой строке ...)
Жиль
@ Денис: если подумать, я могу использовать, shiftесли у меня время правильно.
Жиль
7

Я нашел du --inodesполезным, но я не уверен, какая версия duэтого требует. Это должно быть значительно быстрее, чем использование альтернативных подходов findи wc.

На Ubuntu 17.10 работает следующее:

du --inodes      # all files and subdirectories
du --inodes -s   # summary
du --inodes -d 2 # depth 2 at most

Объединить с | sort -nrсортировать по убыванию по количеству содержащихся inode.

krlmlr
источник
5

При использовании пары ls / wc, если мы добавим -U, это будет намного быстрее (не сортируйте).

ls -AqU | wc -l
Jbnair
источник
1
-Uхотя специфичен для GNU.
Стефан Шазелас
4

После установки команды дерева, просто наберите:

tree

Если вы хотите скрытые файлы тоже:

tree -a

Если вы используете Debian / Mint / Ubuntu Linux, введите следующую команду, чтобы установить команду дерева:

sudo apt-get install tree

Опция -L используется для указания максимального уровня отображения дерева каталогов. Команда дерева не только подсчитывает количество файлов, но и количество каталогов, учитывая столько уровней дерева каталогов, сколько вам нужно.

лев
источник
Когда я набираю дерево, я получаю своего рода вывод дерева на экран каталога, в котором я нахожусь, но я не вижу, где отображается количество файлов.
Чарльздарвин
2
find -maxdepth 1 -type f -printf . | wc -c
  • -maxdepth 1сделает его нерекурсивным, findпо умолчанию рекурсивным
  • -type f будет включать только файлы
  • -printf .это милое прикосновение. он печатает точку для каждого файла вместо имени файла, и теперь он может обрабатывать любое имя файла, а также сохраняет данные; нам просто нужно посчитать точки :)
  • | wc -c считает символы
Од
источник
1

Без трубы, без копирования строк, без форка

$ fcount() { local f i=0; for f in *; do let i++; done; echo $i; }; fcount
DaboD
источник
1
Дает значение 1, если в каталоге нет файлов. Не считает файлы, считает файлы и каталоги.
Стив
1

Вот еще один прием, аналогичный тому, который опубликовал Жиль :

word_count () { local c=("$@"); echo "${#c[@]}"; }
file_count=$(word_count *)

который создает массив с 13 923 элементами (если это количество файлов).

Деннис Уильямсон
источник
Какой смысл в этом cмассиве? word_count() { echo "$#"; }было бы достаточно. Смысл решения @Gilles заключается в том, чтобы сохранить счетчик в возвращаемой переменной, чтобы избежать необходимости использовать подстановку команд (которая включает в себя разветвление и канал в оболочках, отличных от ksh93).
Стефан Шазелас
1
find . -type f -maxdepth 1 |  wc -l 

Это может перечислить только файлы в текущем каталоге.

Pappu
источник
find . -type fнайдет файлы в текущем каталоге, а также, рекурсивно, в подкаталогах.
Даг
0

Попробуйте это, я надеюсь, что этот ответ поможет вам

echo $((`ls -l | wc -l` -1 ))
тигр
источник
0

Вы можете проверить с помощью:

ls -l | grep -v ^l | wc -l
AMIC MING
источник
0

Улучшение некоторых ответов, приведенных ранее, но на этот раз делать явно.

$ tree -L 1 | tail -n 1 | cut -d " " -f 3

Стоит отметить использование некоторых любимых команд, таких как tailи cut. Также обратите внимание, что дерево не доступно по умолчанию. Приведенная выше команда сначала собирает информацию о каталоге на уровне 1, затем получает последнюю строку, в tail -n 1которой находится наша цель, и в итоге cutполучает третье слово.

Например, найти в /:

/ $ tree -L 1
.
├── 1
├── bin -> usr/bin
├── boot
├── dev
├── etc
├── home
├── lib -> usr/lib
├── lib64 -> usr/lib64
├── lost+found
├── media
├── mnt
├── opt
├── proc
├── root
├── run
├── sbin -> usr/sbin
├── srv
├── sys
├── tmp
├── usr
└── var

20 directories, 1 file
/ $ tree -L 1 | tail -n 1
20 directories, 1 file
/ $ tree -L 1 | tail -n 1 | cut -d " " -f 3
1

Тогда как насчет того, чтобы узнать количество каталогов?

jonaprieto
источник
0

В Linux, чтобы сделать команду очень надежной и обрабатывать файлы, в имени которых могут быть символы новой строки, используйте это:

find -maxdepth 1 -type f -print0 | tr -cd '\0' | wc -c

Это спасает нас от суровых испытаний при разборе ls.


Связанный:

codeforester
источник
-2

Используйте treeкоманду, просто:

tree
user115186
источник