Який найкращий спосіб підрахувати кількість файлів у каталозі?


11

Якщо синтаксичний розбір виводу lsє небезпечним, оскільки він може зламатися на деякі фанки (пробіли,, \n...), який найкращий спосіб дізнатися кількість файлів у каталозі?

Я зазвичай покладаюся на те, findщоб уникнути цього розбору, але аналогічно find mydir | wc -lбуде порушено з тих же причин.

Я зараз працюю над Solaris, але шукаю відповідь якомога більш портативною через різні уніці та різні оболонки.


3
Я не впевнений, що це дублікат, я щось пропускаю?
rahmu

1
Це може бути дублікат, але не вказане питання. findотримуватимете кількість файлів рекурсивно (використовуйте, -maxdepth 1якщо цього не хочете. find mydir -maxdepth 1 -type f -printf \\n | wc -lПотрібно обробляти спеціальні символи в імені файлу, оскільки вони ніколи не друкуються.
Anthon

Відповіді:


16

Як щодо цього фокусу?

find . -maxdepth 1 -exec echo \; | wc -l

Як портативний, так findі wc.


5
Це не працює (він відображає n+1файли в моїй системі Debian). Він також не фільтрує звичайні файли.
Кріс Даун

4
Я просто наводив загальний приклад. Це працює, але як це працює, залежить від того, як ви адаптуєте findкоманду до ваших конкретних потреб. Так, до цього входять всі каталоги, в тому числі .(через що ви бачите результат як n+1).
rozcietrzewiacz

Мені подобається ця хитрість, дуже розумна; але я здивований, що немає простого прямого способу зробити це!
rahmu

3
@ChrisDown OP не визначає фільтрацію для звичайних файлів, запитує кількість файлів у каталозі. Щоб позбутися випуску n + 1, використовуйте find . -maxdepth 1 ! -name . -exec echo \; | wc -l; деяких старих версій findне існує -not.
Арседж

3
Зауважте, що -maxdepthце не стандартно (розширення GNU тепер також підтримується кількома іншими реалізаціями).
Стефан Шазелас

11

З bash, без зовнішніх утиліт, а також циклів:

shopt -s dotglob
files=(*)
echo ${#files[@]}

У кш замінити shopt -s dotglobна FIGNORE=.?(.). У zsh замініть його на setopt glob_dotsабо видаліть shoptвиклик та використайте files=(*(D)). (Або просто опустіть рядок, якщо ви не хочете включати крапкові файли.) Портативно, якщо вам не байдуже файли з крапками:

set -- *
echo $#

Якщо ви хочете включити крапкові файли:

set -- *
if [ -e "$1" ]; then c=$#; else c=0; fi
set .[!.]*
if [ -e "$1" ]; then c=$((c+$#)); fi
set ..?*
if [ -e "$1" ]; then c=$((c+$#)); fi
echo $c

2
Перший приклад друкує 1порожній каталог, коли nullglobвін не включений. У Zsh, a=(*(DN));echo ${#a}з N( nullglob) Класифікатор не приводить до помилки для порожнього каталогу.
нісетама

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

Має бути досить портативною для систем після 80-х років.

Це враховує всі записи каталогів, крім .і ..в поточному каталозі.

Для підрахунку файлів також у підкаталогах:

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

(той повинен бути переносним навіть для Unix V6 (1975), оскільки він не потребує -prune)


Один з рідкісних портативних відповідей на цій сторінці, якщо не єдиний.
xhienne

Я відповів на цю відповідь вчора, оскільки виявив, що він також добре працює для каталогів, відмінних від поточного каталогу ( find dirname ! -name dirname -prune -print). Мені з того часу цікаво, чи є якась конкретна причина використовувати grep -c /замість wc -l(що, мабуть, частіше використовується для підрахунку).
Ентоні Геогеган

1
find dirname ! -name dirnameне працює, якщо в ньому є інші каталоги dirname. Краще використовувати find dirname/. ! -name .. wc -lпідраховує кількість рядків, імена файлів можуть складатися з декількох рядків, оскільки символ нового рядка є таким же дійсним, як і будь-який в імені файлу.
Стефан Шазелас

6

Спробуйте:

ls -b1A | wc -l

-bМатиме недруковані символи, -Aбудуть показані всі файли , крім .і ..і один в кожному рядку (за замовчуванням на трубі, але добре , щоб бути явним).

Поки ми включаємо мови сценаріїв вищого рівня, ось один лайнер на Python:

python -c 'import os; print len(os.listdir(os.sep))'

Або з повним "знайти":

python -c 'import os; print len([j for i in os.walk(os.sep) for j in i[1]+i[2]])'

1

Yoc може використовувати таку конструкцію:

I=0; for i in * ; do ((I++)); done ; echo $I

Але я боюся, ви можете помилити помилки, як Argument list too long.у випадку, якщо у вас в каталозі занадто багато файлів. Однак я протестував його в каталозі з 10 мільярдами файлів, і він добре працював.


3
Це не працюватиме і для прихованих файлів, якщо оболонка не налаштована для розширення цих файлів *.
Лекенштейн

gnu find . -maxdepth 1 -type f | wc -l
Nikhil Mulley

4
@Rush: ця команда ніколи не повинна підвищувати "список аргументів занадто довго". Це відбувається лише із зовнішнім командуванням (так ніколи з for.
enzotib

1

Чи розглядали ви perl, який має бути відносно портативним?

Щось на зразок:

use File::Find;

$counter = 0;

sub wanted { 
  -f && ++$counter
}

find(\&wanted, @directories_to_search);
print "$counter\n";

0

Спробуйте це => Використання ls з -i (для номера вузла) & -F (додає ім'я каталогу з параметрами '/').

ls -ilF | egrep -v '/' | wc -l

0

За допомогою perlодного вкладиша (переформатованого для читабельності):

perl -e 'opendir($dh, ".");
         while ( readdir($dh) ) {$count++};
         closedir $dh;
         print "$count\n";'

або

perl -e 'opendir($dh, ".");
         @files = readdir($dh);
         closedir $dh;
         print $#files+1,"\n";'

Ви можете використовувати perlфункції, що змінюють масиви на зразок grepабо mapз другою версією. Див. perldoc -f readdirПриклад використання grep.


0

Найпростіша версія, якою я користуюся весь час і ніколи не мала проблем із цим: ls -b1 | wc -l


Ви можете зіткнутися з проблемами, якщо ім'я файлу містить \nчи інші прикольні символи (так, певні об'єкти дозволяють це).
rahmu

1
Я поставив це явно перед тим, як опублікувати свою відповідь, і не мав проблем з цим. Я використовував менеджер файлів nautilus, щоб перейменувати файл, який міститиме \ n, щоб спробувати це.
Петро

Ти маєш рацію, це не працює так. Я не знаю, що я робив, коли вперше тестував це. Спробував ще раз і оновив свою відповідь.
Петро

Ні, команда в порядку, але вже є подібне рішення і приховані файли не враховуються.
xhienne

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.