Як за допомогою wc та трубопроводів знайти кількість файлів і каталогів у певному каталозі?


10

Як я можу використовувати счетчик слів ( wc) та трубопроводів, щоб підрахувати, скільки файлів чи каталогів є в /usr/binкаталозі?


Це домашнє завдання ?? Добре просити про допомогу, просто визначте її як таку, якщо вона є.
slm

так, але я розміщую тут, щоб отримати уявлення про те, як чогось досягти, оскільки я новачок у Linux, і це може бути дуже складно. І я вже вирішую вищезазначене питання за допомогою цієї команди
готівкою

ls / bin / usr / bin | сортувати | uniq | туалет -
готівка

н.п. Цілком чудово просити допомоги! Просто позначте це, щоб люди знали, що кожен тут радий допомогти людям, які намагаються дізнатись кращі моменти Unix.
slm

Відповіді:


13

Одним із підходів було б скористатися для того, lsщоб надати нам список файлів, але ми хочемо, щоб у цьому списку було відображено лише 1 файл чи каталог у рядку. -1Вимикач робитиме це для нас.

$ ls -1
dir1
dir2
dir3
fileA
fileB
fileC

Приклад

Створіть наведені вище зразки даних у порожньому каталозі.

$ mkdir dir{1..3}
$ touch file{A..C}

Перевір це:

$ ls
dir1  dir2  dir3  fileA  fileB  fileC

Тепер для підрахунку ви можете використовувати wc -lдля підрахунку кількості рядків, які відповідають файлу або каталогу у ls -1висновку.

$ ls -1 | wc -l
6

(проте зауважте, що він не містить прихованих файлів)

Підрахунок файлів чи каталогів, тільки не разом

Для підрахунку файлів чи каталогів потрібно трохи змінити тактику. У цьому випадку я б використовував, ls -lоскільки він показує, що таке каталог та що файл aa.

Приклад

$ ls -l
total 12
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir1
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir2
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir3
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileA
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileB
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileC

Тоді ми можемо використовувати grepдля фільтрації каталогів чи не-каталогів так:

# directories
$ ls -l | grep "^d"
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir1
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir2
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir3

# regular files
$ ls -l | grep "^-"
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileA
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileB
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileC

Тепер просто використовуйте wc -lще раз, щоб порахувати вище:

# directories
$ ls -l | grep "^d" | wc -l
3

# regular files
$ ls -l | grep "^-" | wc -l
3

Хоча, ви можете уникнути в wcцілому, і використання grep«s -cваріанти:

$ ls -l | grep -c '^d'

(знову ж таки, приховані файли не включаються. Зауважте, що каталоги та регулярні файли - це два типи. Є ще багато таких як названі труби, символічні посилання, пристрої, розетки ...).

Рекурсія

Якщо вам потрібно знайти файли та каталоги рекурсивно, /usr/binтоді ви, ймовірно, захочете повністю змінити тактику і скористатися іншим інструментом, який називається find.

Приклад

$ find /usr/bin | wc -l
4632

(хоча вище /usr/binвходить до складу рахунку)

Ті ж методи, які я використовував вище, можна використовувати, lsщоб зробити щось подібне, але, lsяк правило, не є гарним інструментом для аналізу результатів. findз іншого боку, для цього був побудований і пропонує комутатори для пошуку або файлів, або каталогів.

# find files
$ find /usr/bin -type f

# find directories
$ find /usr/bin -type d

(зауважте, що цього разу, findвключаючи приховані файли (крім .і ..)).

нові рядки?

Я ніколи не з'ясовував, чому символ нового рядка є юридичним символом, який слід використовувати при створенні імен файлів або імен каталогів. Тож методи, про які йшлося вище, використовуючи wcі lsне суперечать цим, тому використовуйте їх, маючи на увазі.

Приклад

Створіть каталог та ім’я файлу з новими рядками.

$ mkdir $'dir4\n5'
$ touch $'fileD\nE'

ls показує їх правильно:

$ ls -1
dir1
dir2
dir3
dir4?5
fileA
fileB
fileC
fileD?E

Але wcвважає каталоги та файли, що містять нові рядки, як 2 елементи, а не один.

$ ls -1 | wc -l
10

Один із способів подолати це, якщо використовується реалізація GNU, - findце використовувати findздатність друкувати щось інше замість кожного знайденого файлу, а потім замість них рахувати.

Приклад

$ find . -printf . | wc -c
9

Тут ми знаходимо все в поточному каталозі ( за винятком ..), і друк точка ( .) для кожного, а потім підрахунок точок , використовуючи wcздатність «s для підрахунку байт замість рядків, wc -c.

Список літератури


Хоча всі файли /usr/binбудуть добре відформатовані (а також не містять пробілів, з технічної точки зору, ви могли б навіть просто echo * | wc -w), варто зазначити, що всі вони будуть розбиті на назви файлів, що містять нові рядки.
зол

@evilsoup - ні, я не вірю в те, що не вдасться перебити ls -lчи ls -1/ ми будемо рахувати рядки, а не слова! findМоже зламатися, але знову ж , ми розраховуємо рядки не слово.
slm

Що я маю на увазі, що це (я думаю, я зараз в Windows, тому я не можу перевірити) зламається, якщо файли містять нові рядки . Тож touch $'foo\nbar'у порожньому каталозі, за яким слідує одна з ваших команд (скажімо ls -1 | wc -l), буде повідомлено два файли, а не один - тому що цей файл - це два рядки, наскільки wcце стосується. Якщо тільки не lsзамінює нові рядки якимось іншим символом (я не думаю, що це робить, але я знову не в змозі перевірити зараз).
злий

@evilsoup - правильний, новий рядок. є юридичною умовою. для імен файлів, і методи не зможуть правильно боротися з тими назвами файлів.
slm

@StephaneChazelas - це wc -cпроблема під час підрахунку періодів?
slm

5

Якщо ви хочете отримати кількість даних про файл кожного типу рекурсивно під деяким режимом, за допомогою GNU find, ви можете зробити:

find /some/dir/. ! -name . -printf '%y\n' | sort | uniq -c | sed '
  s/f/regular files/;t
  s/d/directories/;t
  s/l/symbolic links/;t
  s/s/Unix domain sockets/;t
  s/b/block devices/;t
  s/c/character devices/;t
  s/p/FIFOs/;t
  s/D/Doors/;t
  s/n/network special files/;t
  s/.$/others (&)/'

У /usr/binмоїй системі, що дає:

   3727 regular files
    710 symbolic links

Увімкнено /dev:

     83 block devices
    203 character devices
     31 directories
    426 symbolic links
      1 FIFOs
      1 Unix domain sockets

Для символьних посилань, якщо ви краще вважаєте їх типом файлу, на який вони вказують, а не symbolic links, ви можете змінити його на:

find /some/dir/. ! -name . -printf '%Y\n' | sort | uniq -c | sed '
  s/f/regular files/;t
  s/d/directories/;t
  s/N/broken symbolic links/;t
  s/s/Unix domain sockets/;t
  s/b/block devices/;t
  s/c/character devices/;t
  s/p/FIFOs/;t
  s/D/Doors/;t
  s/n/network special files/;t
  s/.$/others (&)/'

Що тепер дає за моє /usr/bin:

      1 directories
   4434 regular files
      2 broken symbolic links

(ламане символьне посилання - це посилання на файл, для якого findне можна визначити тип, тому що файл не існує, або знаходиться в каталозі, до якого ви не маєте доступу, або є петля в роздільній здатності файлу. . У моєму випадку, ті 2, де посилаються на файли, яких тепер немає).

Ніхто з них не рахує .і ... Якщо ви хотіли, щоб вони були включені (чому б вам це зробити?), Немає іншого способу, findніж припустити, що вони є для кожного каталогу та систематично рахувати їх:

find /some/dir/. -printf '%y\n' \( -name . -printf 'd\n' -o \
  -type d -printf 'd\nd\n' \)  | sort | uniq -c | sed '
  s/f/regular files/;t
  s/d/directories/;t
  s/l/symbolic links/;t
  s/s/Unix domain sockets/;t
  s/b/block devices/;t
  s/c/character devices/;t
  s/p/FIFOs/;t
  s/D/Doors/;t
  s/n/network special files/;t
  s/.$/others (&)/'

Що потім дає на моє /usr/bin:

      2 directories
   3727 regular files
    710 symbolic links

Якщо у вас немає доступу до GNU find, ви можете переписати перший як:

find /some/dir/. ! -name . \( \
  -type f -exec printf '%.0sregular files\n' {} + -o \
  -type d -exec printf '%.0sdirectories\n' {} + -o \
  -type l -exec printf '%.0ssymbolic links\n' {} + -o \
  -type s -exec printf '%.0sUnix domain sockets\n' {} + -o \
  -type b -exec printf '%.0sblock devices\n' {} + -o \
  -type c -exec printf '%.0scharacter devices\n' {} + -o \
  -type p -exec printf '%.0sFIFOs\n' {} + -o \
  -exec printf '%.0sothers\n' {} + \) | sort | uniq -c

Тепер, строго кажучи, ми рахували не файли, а записи каталогів . Каталог, як /usr/binправило, має кілька записів, які вказують на один і той же файл. Наприклад, тут я маю:

$ ls -lid /usr/bin/{nvi,nview,nex}
672252 -rwxr-xr-x 3 root root 434616 May 25 07:40 /usr/bin/nex
672252 -rwxr-xr-x 3 root root 434616 May 25 07:40 /usr/bin/nvi
672252 -rwxr-xr-x 3 root root 434616 May 25 07:40 /usr/bin/nview

Це 3 записи каталогів (імена файлів ака ж жорсткі посилання) на той самий файл (той, який має inode 672252. Для підрахунку файлів замість записів каталогів та з GNU findта GNU uniq(ігнорування .та ..файли, які так чи інакше є жорсткими посиланнями на інші каталоги):

find /some/dir/. ! -name . -printf '%y\t%D:%i\n' |
  sort -u |
  cut -f1 |
  uniq -c |
  sed '
    s/f/regular files/;t
    s/d/directories/;t
    s/l/symbolic links/;t
    s/s/Unix domain sockets/;t
    s/b/block devices/;t
    s/c/character devices/;t
    s/p/FIFOs/;t
    s/d/Doors/;t
    s/n/network special files/;t
    s/.$/others (&)/'

По моєму /usr/bin, це дає:

   3711 regular files
    710 symbolic links

0

Ви ще не говорили, чи хочете, щоб весь файл під / usr / bin був рекурсивно або просто під першим рівнем. Крім того, як ви збираєтеся отримати слова, які ви рахуєте? Звичайний спосіб з'ясувати це запустити пошук у туалет. Ось так: знайти / usr / bin | wc -l Find перерахує все там, каталоги та файли. Wc -l буде рахувати всі рядки у знаходженні результатів. Це завдання для класу? Це нормально, якщо це так, але мені було цікаво, навіщо вам потрібна ця інформація, щоб я міг більш ретельно адаптувати відповідь. Будь ласка, дайте мені знати, якщо вам потрібно більше. Коста


0

Баш, без зовнішніх інструментів.

cd dir/ || exit; shopt -s nullglob; shopt -s dotglob; count=(*); echo "${#count}"

Баш, без зовнішніх інструментів та рекурсії.

shopt -s globstar; shopt -s dotglob 
for dir in **/*/; do 
  unset d f
  for files in "$dir"*; do 
    [[ -f $files ]] && ((++f))
    [[ -d $files ]] && ((++d))
  done; 
  printf '%s\n' "$dir -  files: ${f:-0} - directories: ${d:-0}"
done

Зауважте, що другий буде повторювати символьні посилання при повторному повторенні (і рахувати символьні посилання на звичайні файли як звичайні файли, а посилання на dirs як dirs), не рахуватиме файли та каталоги в поточному каталозі і не буде рахувати .ані ..записи. Ви можете роз’єднати файл проти звичайного файлу.
Стефан Шазелас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.