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


194

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



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 - <номер-один> | туалет - <буква-л>


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)


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.


5

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

ls -AqU | wc -l

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

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 

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


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

0

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

echo $((`ls -l | wc -l` -1 ))


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

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


0

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

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

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


Связанный:


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.