Відповіді:
Цей простий однолінійний апарат повинен працювати в будь-якій оболонці, а не лише в bash:
ls -1q log* | wc -l
ls -1q дасть вам один рядок на файл, навіть якщо вони містять пробіл або спеціальні символи, такі як нові рядки.
Вихід подається на wc -l, що рахує кількість рядків.
ls, оскільки це створює дитячий процес. log*розширюється оболонкою, не lsтак, як це echoбуло б просто .
logs, то вміст цього каталогу журналів також буде врахований. Мабуть, це не навмисно.
Ви можете зробити це безпечно (тобто не буде помилятися файлами з пробілами або \nв їх імені) за допомогою bash:
$ shopt -s nullglob
$ logfiles=(*.log)
$ echo ${#logfiles[@]}
Потрібно ввімкнути nullglobтак, щоб *.logу $logfiles масиві не потрапляв буквал, якщо жоден файл не збігається. (Див. Як "скасувати" "set -x"? Для прикладів безпечного скидання.)
shopt -u nullglobслід пропустити, якщо nullglobйого не було встановлено, тоді ви почали.
*.logпростою *буде рахувати каталоги. Якщо файли, які ви хочете перерахувати, мають традиційну угоду про іменування name.extension, використовуйте *.*.
Тут багато відповідей, але деякі не беруть до уваги
-l)*.logзамість цього була глобус )log*logsщо матчі log*)Ось рішення, яке стосується всіх:
ls 2>/dev/null -Ubad1 -- log* | wc -l
Пояснення:
-Uзмушує lsне сортувати записи, тобто не потрібно завантажувати весь список каталогу в пам'ять-bдрукує вивіски у стилі С для неграфічних символів, що вирішально спричиняє друк нових рядків \n.-aдрукує всі файли, навіть приховані файли (не суворо необхідні, коли глобул log*не має на увазі прихованих файлів)-dвиводить каталоги, не намагаючись перерахувати вміст каталогу, що lsзазвичай робиться-1 гарантує, що він знаходиться на одному стовпчику (ls робить це автоматично під час запису в трубу, тому це не є строго необхідним)2>/dev/nullперенаправляє stderr, щоб, якщо є 0 журнальних файлів, ігноруйте повідомлення про помилку. (Зверніть увагу, що shopt -s nullglobце призведе lsдо того, щоб перерахувати весь робочий каталог замість цього.)wc -lспоживає лістинг каталогів під час його генерування, тому виведення даних lsніколи не залишається в пам'яті в будь-який момент часу.--Імена файлів відокремлюються від команди за допомогою, --щоб не розумітись як аргументи ls(у разі log*видалення)Оболонка буде розширюватися log*в повний список файлів, які можуть вичерпати пам'ять , якщо багато файлів, тому потім запустити його через Grep це краще:
ls -Uba1 | grep ^log | wc -l
Цей останній обробляє надзвичайно великі каталоги файлів, не використовуючи багато пам’яті (хоч він і використовує доподібну оболонку). Це -dбільше не потрібно, оскільки він лише перераховує вміст поточного каталогу.
Для рекурсивного пошуку:
find . -type f -name '*.log' -printf x | wc -c
wc -cбуде підраховувати кількість символів на виході find, при цьому -printf xповідомляє findнадрукувати одиницю xдля кожного результату.
Для нерекурсивного пошуку зробіть це:
find . -maxdepth 1 -type f -name '*.log' -printf x | wc -c
-name '*.log'то він буде рахувати всі файли, що мені потрібно для мого використання. Також прапор -maxdepth надзвичайно корисний, дякую!
find; просто надрукуйте щось інше, ніж дословне ім'я файлу.
Прийнята відповідь на це питання неправильна, але у мене низька відповідь, тому я не можу до цього коментаря додати коментар.
Правильну відповідь на це питання дає Мат:
shopt -s nullglob
logfiles=(*.log)
echo ${#logfiles[@]}
Проблема з прийнятою відповіддю полягає в тому, що wc -l підраховує кількість символів нового рядка і рахує їх, навіть якщо вони друкують на терміналі як "?" у висновку 'ls -l'. Це означає, що прийнята відповідь не відповідає, коли ім'я файлу містить символ нового рядка. Я перевірив запропоновану команду:
ls -l log* | wc -l
і він помилково повідомляє значення 2, навіть якщо є лише 1 файл, що відповідає шаблону, ім'я якого містить символ нового рядка. Наприклад:
touch log$'\n'def
ls log* -l | wc -l
Якщо у вас багато файлів, і ви не хочете використовувати елегантне рішення shopt -s nullglobі bash-масив, ви можете використовувати find і так далі, поки ви не роздрукуєте ім'я файлу (який може містити нові рядки).
find -maxdepth 1 -name "log*" -not -name ".*" -printf '%i\n' | wc -l
Тут знайдуться всі файли, які відповідають журналу * і які не починаються з .*- "не ім'я. для знаходження - це включити їх.
Це правильна відповідь і обробляє будь-який тип імені файлу, який ви можете кинути на нього, оскільки ім'я файлу ніколи не передається між командами.
Але, shopt nullglobвідповідь - найкраща відповідь!
findvs використовує lsдва різні способи вирішення проблеми. findне завжди присутній на машині, але lsзазвичай є,
findмабуть, не має всіх цих фантазійних варіантів ls.
-maxdepth 1
findробить це за замовчуванням Це може створити плутанину, якщо хтось не зрозуміє, що є прихована дочірня папка, і може зробити її вигідною lsв деяких випадках, яка не повідомляє про приховані файли за замовчуванням.
Ось мій один лайнер для цього.
file_count=$( shopt -s nullglob ; set -- $directory_to_search_inside/* ; echo $#)
set -- нічого не робимо, окрім того, як ми готові до того $#, що зберігається кількість аргументів командного рядка, переданих програмі оболонки
(недостатньо репутації для коментарів)
Це БУГІ :
ls -1q some_pattern | wc -l
Якщо shopt -s nullglobце станеться встановленим, воно друкує кількість ВСІХ звичайних файлів, а не лише тих, що мають шаблон (протестовано на CentOS-8 та Cygwin). Хто знає, які інші безглузді помилки lsє?
Це ПРАВИЛЬНО і набагато швидше:
shopt -s nullglob; files=(some_pattern); echo ${#files[@]};
Це робить очікувану роботу.
0.006на CentOS і 0.083на Cygwin (на випадок, якщо вони використовуються обережно).
0.000на CentOS і 0.003на Cygwin.
Ви можете легко визначити таку команду, використовуючи функцію оболонки. Цей метод не вимагає жодної зовнішньої програми і не породжує жодного дочірнього процесу. Він не намагається небезпечно lsрозібратись та обробляє "особливі" символи (пробіли, нові рядки, косої риски тощо) просто чудово. Він покладається лише на механізм розширення імені файлів, наданий оболонкою. Він сумісний принаймні з sh, bash та zsh.
Рядок нижче визначає функцію, countяка називається, яка друкує кількість аргументів, з якими вона була викликана.
count() { echo $#; }
Просто зателефонуйте йому за потрібним малюнком:
count log*
Щоб результат був правильним, коли шаблон глобалізації не відповідає, параметр оболонки nullglob(або failglob- що є типовою поведінкою для zsh) повинен бути встановлений у момент розширення часу. Його можна встановити так:
shopt -s nullglob # for sh / bash
setopt nullglob # for zsh
Залежно від того, що ви хочете порахувати, вам може бути цікавий варіант оболонки dotglob.
На жаль, з bash принаймні, налаштувати ці параметри локально непросто. Якщо ви не хочете встановлювати їх у всьому світі, найпростішим рішенням є використання функції таким більш стислим способом:
( shopt -s nullglob ; shopt -u failglob ; count log* )
Якщо ви хочете відновити полегшений синтаксис count log*або якщо ви дійсно хочете уникнути нересту неділі, ви можете зламати щось у відповідності з:
# sh / bash:
# the alias is expanded before the globbing pattern, so we
# can set required options before the globbing gets expanded,
# and restore them afterwards.
count() {
eval "$_count_saved_shopts"
unset _count_saved_shopts
echo $#
}
alias count='
_count_saved_shopts="$(shopt -p nullglob failglob)"
shopt -s nullglob
shopt -u failglob
count'
Як бонус, ця функція має більш загальне використання. Наприклад:
count a* b* # count files which match either a* or b*
count $(jobs -ps) # count stopped jobs (sh / bash)
При повороті функції в файл сценарію (або еквівалентну програму C), що викликається з PATH, він також може бути складений з такими програмами, як findі xargs:
find "$FIND_OPTIONS" -exec count {} \+ # count results of a search
Я багато роздумував над цією відповіддю, особливо зважаючи на матеріали, які не аналізуються . Спочатку я спробував
<ПОПЕРЕДЖЕННЯ! НЕ РОБОТИ>
du --inodes --files0-from=<(find . -maxdepth 1 -type f -print0) | awk '{sum+=int($1)}END{print sum}'
</ ПОПЕРЕДЖЕННЯ! НЕ РОБОТИ>
який працював, якщо було лише ім’я файлу на зразок
touch $'w\nlf.aa'
але не вдалося, якщо я створив таке ім'я файлу
touch $'firstline\n3 and some other\n1\n2\texciting\n86stuff.jpg'
Нарешті я придумав те, що викладаю нижче. Примітка. Я намагався отримати кількість всіх файлів у каталозі (не включаючи підкаталогів). Я думаю, що це, поряд з відповідями @Mat та @Dan_Yard, а також з принаймні більшістю вимог, викладених @mogsie (я не впевнений у пам’яті.) Я вважаю, що відповідь @mogsie є правильною, але я завжди намагаюся триматися подалі від розбору, lsякщо це не надзвичайно конкретна ситуація.
awk -F"\0" '{print NF-1}' < <(find . -maxdepth 1 -type f -print0) | awk '{sum+=$1}END{print sum}'
Більш зрозуміло:
awk -F"\0" '{print NF-1}' < \
<(find . -maxdepth 1 -type f -print0) | \
awk '{sum+=$1}END{print sum}'
Це робиться знахідка спеціально для файлів, розмежуючи висновок з нульовим символом (щоб уникнути проблем з пробілами та стрічковими каналами), а потім підраховувати кількість нульових символів. Кількість файлів буде на одну меншу, ніж кількість нульових символів, оскільки в кінці буде нульовий символ.
Щоб відповісти на питання ОП, слід розглянути два випадки
1) Нерекурсивний пошук:
awk -F"\0" '{print NF-1}' < \
<(find . -maxdepth 1 -type f -name "log*" -print0) | \
awk '{sum+=$1}END{print sum}'
2) рекурсивний пошук. Зауважте, що те, що знаходиться всередині -nameпараметра, може знадобитися змінити для дещо іншої поведінки (прихованих файлів тощо).
awk -F"\0" '{print NF-1}' < \
<(find . -type f -name "log*" -print0) | \
awk '{sum+=$1}END{print sum}'
Якщо хтось хотів би прокоментувати, як ці відповіді порівнюються з тими, про які я згадував у цій відповіді, будь ласка, зробіть це.
Зауважте, я потрапив до цього роздуму, отримуючи цю відповідь .
ls -1 log* | wc -l
Що означає перерахувати один файл на рядок, а потім передати його команді count count з переключенням параметрів на лічильник рядків.
-l, оскільки це вимагаєstat(2)для кожного файлу і для підрахунку не додає нічого.