Мені потрібно перевірити всі підкаталоги та повідомити, скільки файлів (без подальшої рекурсії) вони містять:
directoryName1 numberOfFiles
directoryName2 numberOfFiles
Мені потрібно перевірити всі підкаталоги та повідомити, скільки файлів (без подальшої рекурсії) вони містять:
directoryName1 numberOfFiles
directoryName2 numberOfFiles
Відповіді:
Це робить це безпечним і портативним способом. Це не заплутається дивними іменами.
for f in *; do [ -d ./"$f" ] && find ./"$f" -maxdepth 1 -exec echo \; | wc -l && echo $f; done
Зверніть увагу, що спочатку буде надруковано кількість файлів, а потім ім'я каталогу в окремому рядку. Якщо ви хочете зберегти формат ОП, вам знадобиться подальше форматування, наприклад
for f in *; do [ -d ./"$f" ] && find ./"$f" -maxdepth 1 -exec echo \;|wc -l|tr '\n' ' ' && echo $f; done|awk '{print $2"\t"$1}'
Якщо у вас є певний набір цікавих підкаталогів, ви можете замінити *
їх.
Чому це безпечно? (і тому сценарій гідний)
Імена файлів можуть містити будь-який символ, крім /
. Є кілька символів, які спеціально обробляються або оболонкою, або командами. До них відносяться пробіли, нові рядки та тире.
Використання for f in *
конструкції - це безпечний спосіб отримання кожного імені файлу, незалежно від того, що він містить.
Коли у вас є ім'я файлу в змінній, вам все одно доведеться уникати таких речей find $f
. Якщо воно $f
містило б ім'я файлу -test
, find
скаржиться на варіант, який ви йому щойно надали. Спосіб уникнути цього - використання ./
перед іменем; таким чином він має те саме значення, але він більше не починається з тире.
Нові рядки та пробіли також є проблемою. Якщо $f
міститься "привіт, приятель" як ім'я файлу find ./$f
, є find ./hello, buddy
. Ти кажеш find
подивитися ./hello,
і buddy
. Якщо їх не існує, він скаржиться, і він ніколи не загляне ./hello, buddy
. Це легко уникнути - використовуйте лапки навколо змінних.
Нарешті, імена файлів можуть містити нові рядки, тому підрахунок нових рядків у списку імен не буде працювати; ви отримаєте додатковий підрахунок для кожного імені файлу з новим рядком. Щоб уникнути цього, не рахуйте нові рядки у списку файлів; натомість порахуйте нові рядки (або будь-який інший символ), що представляє один файл. Ось чому find
команда просто -exec echo \;
і ні -exec echo {} \;
. Я хочу надрукувати лише один новий рядок з метою підбору файлів.
-mindepth 1
-printf '\n'
замість -exec echo
.
-printf
, але не, якщо ви хочете, щоб він працював на FreeBSD, наприклад.
Якщо припустити, що ви шукаєте стандартне рішення для Linux, то це досить просто find
:
find dir1/ dir2/ -maxdepth 1 -type f | wc -l
Там, де find
проходять два зазначені підкаталоги, до -maxdepth
числа 1, що запобігає подальшій рекурсії, і лише повідомляє файли ( -type f
), розділені новими рядками. Потім результат передається wc
для підрахунку кількості цих рядків.
find . -maxdepth 1 -type d
результатом?
find $dirs ...
або, (b) якщо вони є виключно в одному каталозі вищого рівня, глобусі з цього каталогу,find */ ...
-exec echo
до команди пошуку - таким чином вона не буде перегукуватися з іменем файлу, а лише з новим рядком.
Під "без рекурсії" ви маєте на увазі, що якщо directoryName1
є підкаталоги, то ви не хочете рахувати файли в підкаталогах? Якщо так, ось спосіб підрахунку всіх регулярних файлів у зазначених каталогах:
count=0
for d in directoryName1 directoryName2; do
for f in "$d"/* "$d"/.[!.]* "$d"/..?*; do
if [ -f "$f" ]; then count=$((count+1)); fi
done
done
Зауважте, що -f
тест виконує дві функції: він перевіряє, чи є запис, узгоджений одним із глобусів вище, звичайним файлом, і перевіряє, чи була відповідність запису (якщо один із глобусів нічого не відповідає, шаблон залишається таким, як є¹). Якщо ви хочете порахувати всі записи в даних каталогах незалежно від їх типу, замініть -f
на -e
.
У Ksh є можливість зразки збігатися з крапковими файлами та створювати порожній список, якщо жоден файл не відповідає шаблону. Тож у ksh ви можете порахувати звичайні файли на зразок цього:
FIGNORE='.?(.)'
count=0
for x in ~(N)directoryName1/* ~(N)directoryName2/*; do
if [ -f "$x" ]; then ((++count)); fi
done
або всі файли просто так:
FIGNORE='.?(.)'
files=(~(N)directoryName1/* ~(N)directoryName2/*)
count=${#files}
У Bash є різні способи зробити це простішим. Для підрахунку звичайних файлів:
shopt -s dotglob nullglob
count=0
for x in directoryName1/* directoryName2/*; do
if [ -f "$x" ]; then ((++count)); fi
done
Для підрахунку всіх файлів:
shopt -s dotglob nullglob
files=(directoryName1/* directoryName2/*)
count=${#files}
Як завжди, в zsh це навіть простіше. Для підрахунку звичайних файлів:
files=({directoryName1,directoryName2}/*(DN.))
count=$#files
Змінити, (DN.)
щоб (DN)
рахувати всі файли.
¹ Зауважте, що кожен шаблон відповідає самій собі, інакше результати можуть бути вимкнені (наприклад, якщо ви рахуєте файли, які починаються з цифри, ви не можете просто зробити це, for x in [0-9]*; do if [ -f "$x" ]; then …
тому що може бути названий файл [0-9]foo
).
На основі сценарію підрахунку , відповіді Шона та хитрості Баша, щоб переконатися, що навіть імена файлів з новими рядками друкуються в зручній формі в одному рядку:
for f in *
do
if [ -d "./$f" ]
then
printf %q "$f"
printf %s ' '
find "$f" -maxdepth 1 -printf x | wc -c
fi
done
printf %q
полягає в тому, щоб надрукувати цитовану версію рядка, тобто однорядковий рядок, який ви можете ввести в сценарій Bash, щоб його інтерпретувати як буквальний рядок, що включає (потенційно) нові рядки та інші спеціальні символи. Наприклад, див echo -n $'\tfoo\nbar'
проти printf %q $'\tfoo\nbar'
.
find
Команда працює, просто друк одного символу для кожного файлу, а потім рахуючи тих , замість підрахунку рядків.
Ось «груба сила» -ish спосіб отримати результат, використовуючи find
, echo
, ls
, wc
, xargs
і awk
.
find . -maxdepth 1 -type d -exec sh -c "echo '{}'; ls -1 '{}' | wc -l" \; | xargs -n 2 | awk '{print $1" "$2}'
for i in *; do echo $i; ls $i | wc -l; done
for i in `ls -1`; do echo $i : `ls -1 $i|wc -l`; done
find
коли Bash зробить це?(shopt -s dotglob; for dir in */; do all=("$dir"/*); echo "$dir: ${#all[@]}"; done)
: для всіх каталогів підраховуйте кількість записів у цьому каталозі (включаючи приховані точкові файли, виключаючи.
та..
)