Соответствующая последовательность системных запросов для перезагрузки аналогична.
O 'Off' заменяется на B 'Boot'.
Нажимайте одновременно клавиши alt и PrintScreen и одну из клавиш REISUO один за другим.Нажимайте одновременно клавиши alt и PrintScreen и одну из клавиш REISUO медленно.
Если это ноутбук, вам также может потребоваться нажать клавишу Fn, например так: Нажмите три клавиши Fn и alt и клавиши PrintScreen все время и одну из клавиш REISUO один за другим медленно.на ноутбуке, возможно, три клавиши Fn и alt и PrintScreen все время
Для получения более подробной информации см. следующие ссылки,
Перезапустите Ubuntu с клавиатуры
Я не изучал вывод с символическими ссылками, но:
find . -type f -iname '*.c' -printf '%h\0' |
sort -z |
uniq -zc |
sed -zr 's/([0-9]) .*/\1 1/' |
tr '\0' '\n' |
awk '{f += $1; d += $2} END {print f, d}'
Команда find печатает имя каталога каждого найденного файла .c. sort | uniq -c предоставит нам, сколько файлов находится в каждом каталоге (здесь sort может быть ненужным, а не обязательно) с помощью sed, я заменяю имя каталога на 1, тем самым устраняя все возможные странные символы, счетчик и 1 останутся, позволяя мне преобразовать вывод, выделенный в новую строку, с помощью tr, который затем я суммирую с awk, чтобы получить общее количество файлов и количество каталогов, содержащих эти файлы. Обратите внимание, что d здесь по существу совпадает с NR. Я мог бы пропустить вставку 1 в команду sed и просто напечатать NR здесь, но я думаю, что это немного яснее. До tr данные делятся на NUL, безопасны для всех допустимых имен файлов.
С помощью zsh и bash вы можете использовать [ f19], чтобы получить строку с кавычками, в которой не было бы новых строк. Таким образом, вы можете сделать что-то вроде:
shopt -s globstar dotglob nocaseglob
printf "%q\n" **/*.c | awk -F/ '{NF--; f++} !c[$0]++{d++} END {print f, d}'
Однако, хотя ** не предполагается расширять для символических ссылок на каталоги, я не смог получить желаемый результат в bash 4.4.18 (1) (Ubuntu 16.04).
$ shopt -s globstar dotglob nocaseglob
$ printf "%q\n" ./**/*.c | awk -F/ '{NF--; f++} !c[$0]++{d++} END {print f, d}'
34 15
$ echo $BASH_VERSION
4.4.18(1)-release
Но zsh работал нормально, и команда может быть упрощена:
$ printf "%q\n" ./**/*.c(D.:h) | awk '!c[$0]++ {d++} END {print NR, d}'
29 7
D позволяет этому глобусу выбирать точечные файлы , . выбирает обычные файлы (так, а не символические ссылки), а :h печатает только путь к каталогу, а не имя файла (например, find %h) (см. разделы ** не предполагается расширить для символических ссылок на каталоги и модификаторы). Таким образом, с помощью команды awk нам просто нужно подсчитать количество уникальных каталогов, а количество строк - количество файлов.
Я не изучал вывод с символическими ссылками, но:
find . -type f -iname '*.c' -printf '%h\0' |
sort -z |
uniq -zc |
sed -zr 's/([0-9]) .*/\1 1/' |
tr '\0' '\n' |
awk '{f += $1; d += $2} END {print f, d}'
Команда find печатает имя каталога каждого найденного файла .c. sort | uniq -c предоставит нам, сколько файлов находится в каждом каталоге (здесь sort может быть ненужным, а не обязательно) с помощью sed, я заменяю имя каталога на 1, тем самым устраняя все возможные странные символы, счетчик и 1 останутся, позволяя мне преобразовать вывод, выделенный в новую строку, с помощью tr, который затем я суммирую с awk, чтобы получить общее количество файлов и количество каталогов, содержащих эти файлы. Обратите внимание, что d здесь по существу совпадает с NR. Я мог бы пропустить вставку 1 в команду sed и просто напечатать NR здесь, но я думаю, что это немного яснее. До tr данные делятся на NUL, безопасны для всех допустимых имен файлов.
С помощью zsh и bash вы можете использовать printf %q, чтобы получить строку с кавычками, в которой не было бы новых строк. Таким образом, вы можете сделать что-то вроде:
shopt -s globstar dotglob nocaseglob
printf "%q\n" **/*.c | awk -F/ '{NF--; f++} !c[$0]++{d++} END {print f, d}'
Однако, хотя ** не предполагается расширять для символических ссылок на каталоги, я не смог получить желаемый результат в bash 4.4.18 (1) (Ubuntu 16.04).
$ shopt -s globstar dotglob nocaseglob
$ printf "%q\n" ./**/*.c | awk -F/ '{NF--; f++} !c[$0]++{d++} END {print f, d}'
34 15
$ echo $BASH_VERSION
4.4.18(1)-release
Но zsh работал нормально, и команда может быть упрощена:
$ printf "%q\n" ./**/*.c(D.:h) | awk '!c[$0]++ {d++} END {print NR, d}'
29 7
D позволяет этому глобусу выбирать точечные файлы , . выбирает обычные файлы (так, а не символические ссылки), а :h печатает только путь к каталогу, а не имя файла (например, find %h) (см. разделы ** не предполагается расширить для символических ссылок на каталоги и модификаторы). Таким образом, с помощью команды awk нам просто нужно подсчитать количество уникальных каталогов, а количество строк - количество файлов.
Я не изучал вывод с символическими ссылками, но:
find . -type f -iname '*.c' -printf '%h\0' |
sort -z |
uniq -zc |
sed -zr 's/([0-9]) .*/\1 1/' |
tr '\0' '\n' |
awk '{f += $1; d += $2} END {print f, d}'
Команда find печатает имя каталога каждого найденного файла .c. sort | uniq -c предоставит нам, сколько файлов находится в каждом каталоге (здесь sort может быть ненужным, а не обязательно) с помощью sed, я заменяю имя каталога на 1, тем самым устраняя все возможные странные символы, счетчик и 1 останутся, позволяя мне преобразовать вывод, выделенный в новую строку, с помощью tr, который затем я суммирую с awk, чтобы получить общее количество файлов и количество каталогов, содержащих эти файлы. Обратите внимание, что d здесь по существу совпадает с NR. Я мог бы пропустить вставку 1 в команду sed и просто напечатать NR здесь, но я думаю, что это немного яснее. До tr данные делятся на NUL, безопасны для всех допустимых имен файлов.
С помощью zsh и bash вы можете использовать printf %q, чтобы получить строку с кавычками, в которой не было бы новых строк. Таким образом, вы можете сделать что-то вроде:
shopt -s globstar dotglob nocaseglob
printf "%q\n" **/*.c | awk -F/ '{NF--; f++} !c[$0]++{d++} END {print f, d}'
Однако, хотя ** не предполагается расширять для символических ссылок на каталоги, я не смог получить желаемый результат в bash 4.4.18 (1) (Ubuntu 16.04).
$ shopt -s globstar dotglob nocaseglob
$ printf "%q\n" ./**/*.c | awk -F/ '{NF--; f++} !c[$0]++{d++} END {print f, d}'
34 15
$ echo $BASH_VERSION
4.4.18(1)-release
Но zsh работал нормально, и команда может быть упрощена:
$ printf "%q\n" ./**/*.c(D.:h) | awk '!c[$0]++ {d++} END {print NR, d}'
29 7
D позволяет этому глобусу выбирать точечные файлы , . выбирает обычные файлы (так, а не символические ссылки), а :h печатает только путь к каталогу, а не имя файла (например, find %h) (см. разделы ** не предполагается расширить для символических ссылок на каталоги и модификаторы). Таким образом, с помощью команды awk нам просто нужно подсчитать количество уникальных каталогов, а количество строк - количество файлов.
Python имеет os.walk, что делает такие задачи такими же легкими, интуитивно понятными и автоматически надежными даже перед лицом странных имен файлов, таких как те, которые содержат символы новой строки. Этот сценарий Python 3, который я изначально разместил в чате, предназначен для запуска в текущем каталоге (но он не должен находиться в текущем каталоге, и вы можете изменить его путь к os.walk), :
#!/usr/bin/env python3
import os
dc = fc = 0
for _, _, fs in os.walk('.'):
c = sum(f.endswith('.c') for f in fs)
if c:
dc += 1
fc += c
print(dc, fc)
Это печатает количество каталогов, в которых содержится хотя бы один файл, имя которого заканчивается на .c, за которым следует пробел, за которым следует количество файлов, имена которых заканчиваются на .c , «Скрытые» файлы, то есть файлы, имена которых начинаются с ., включены, а скрытые каталоги аналогичным образом пересекаются.
os.walk Он перечисляет все каталоги, которые рекурсивно доступны из исходной точки, которую вы им даете, приводя информацию о каждом из них как кортеж из трех значений root, dirs, files. Для каждого каталога он переходит к (включая первый, имя которого вы даете ему):
root содержит путь к этому каталогу. Обратите внимание, что это абсолютно не связано с «корневым каталогом» системы / (а также не связано с /root), хотя оно будет идти к тем, если вы начнете там. В этом случае root начинается с пути . - i.e., Текущего каталога - и проходит повсюду под ним. dirs содержит список путей всех подкаталогов каталога, имя которого в настоящее время хранится в root. files содержит список путей всех файлов, которые находятся в каталоге, имя которого в настоящее время хранится в root, но которые не являются самими каталогами. Обратите внимание, что это включает в себя другие типы файлов, чем обычные файлы, включая символические ссылки, но похоже, что вы не ожидаете окончания таких записей в .c и заинтересованы в том, чтобы видеть что-либо подобное.В этом случае мне нужно только изучить третий элемент кортежа, files (который я называю fs в скрипте). Как и команда find, Python os.walk перемещается в подкаталоги для меня; единственное, что я должен проверить сам, это имена файлов, в которые каждый из них содержится. В отличие от команды find, os.walk автоматически предоставляет мне список этих имен файлов.
Этот скрипт не соответствует символическим ссылкам. Вы, вероятно, , что хотите, чтобы для такой операции были использованы символические ссылки, потому что они могли образовывать циклы, и поскольку даже если нет циклов, одни и те же файлы и каталоги могут проходить и подсчитываться несколько раз, если они доступны через различные символические ссылки.
Если вы когда-либо хотели os.walk следовать символическим ссылкам, что вы обычно не хотели, то вы можете передать followlinks=true на него. То есть вместо записи os.walk('.') вы можете написать os.walk('.', followlinks=true). Я повторяю, что вы редко этого хотели, особенно для такой задачи, в которой вы рекурсивно перечисляете всю структуру каталогов, независимо от того, насколько она велика, и подсчитывая все файлы в ней, которые удовлетворяют некоторым требованиям.
Найти + Perl:
$ find . -type f -iname '*.c' -printf '%h\0' |
perl -0 -ne '$k{$_}++; }{ print scalar keys %k, " $.\n" '
7 29
Команда find найдет любые обычные файлы (так что никаких символических ссылок или каталогов), а затем напечатать имя каталога, которое они находятся в (%h), а затем \0.
perl -0 -ne: прочитайте ввод строки за строкой (-n) и примените скрипт, заданный -e для каждой строки. [F9] устанавливает разделитель входных строк на \0, чтобы мы могли считывать ввод с нулевым ограничением. $k{$_}++: $_ - специальная переменная, которая принимает значение текущей строки. Это используется как ключ к хешу %k, значения которого представляют собой количество раз, когда была видна каждая строка ввода (имя каталога). }{: это сокращенный способ написания END{}. Любые команды после }{ будут выполняться один раз, после того, как все данные будут обработаны. print scalar keys %k, " $.\n": keys %k возвращает массив ключей в хеше %k. scalar keys %k дает количество элементов в этом массиве, количество просмотренных каталогов. Это печатается вместе с текущим значением $., специальной переменной, которая содержит текущий номер строки ввода. Так как это выполняется в конце, текущий номер строки ввода будет номером последней строки, поэтому количество строк, видимых до сих пор.Вы можете расширить команду perl для этого, для ясности:
find . -type f -iname '*.c' -printf '%h\0' |
perl -0 -e 'while($line = <STDIN>){
$dirs{$line}++;
$tot++;
}
$count = scalar keys %dirs;
print "$count $tot\n" '
Вот мое предложение:
#!/bin/bash
tempfile=$(mktemp)
find -type f -name "*.c" -prune >$tempfile
grep -c / $tempfile
sed 's_[^/]*$__' $tempfile | sort -u | grep -c /
Этот короткий скрипт создает временный файл, находит каждый файл в и под текущим каталогом, заканчивающимся на .c, и записывает список в файл temp. grep затем используется для подсчета файлов (следуя Как я могу получить количество файлов в каталоге с помощью командной строки?) дважды: во второй раз каталоги, которые перечислены несколько раз, удаляются с помощью sort -u после удаления файлов из каждой строки, используя sed.
Это также корректно работает с новыми строками в именах файлов: grep -c / подсчитывает только строки с косой чертой и поэтому учитывает только первую строку многострочного имени файла в списке.
$ tree
.
├── 1
│ ├── 1
│ │ ├── test2.c
│ │ └── test.c
│ └── 2
│ └── test.c
└── 2
├── 1
│ └── test.c
└── 2
$ tempfile=$(mktemp);find -type f -name "*.c" -prune >$tempfile;grep -c / $tempfile;sed 's_[^/]*$__' $tempfile | sort -u | grep -c /
4
3
Я предлагаю небольшой командный столбец bash с двумя основными командами (и переменной filetype, чтобы было легко переключиться, чтобы искать другие типы файлов).
Он не ищет или в символических ссылках, только обычные файлы.
#!/bin/bash
filetype=c
#filetype=pdf
# count the 'filetype' files
find -type f -name "*.$filetype" -ls|sed 's#.* \./##'|wc -l | tr '\n' ' '
# count directories containing 'filetype' files
find -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)'" \;|grep 'contains file(s)$'|wc -l
Это более подробная версия, которая также рассматривает символические ссылки, [!d4 ]
#!/bin/bash
filetype=c
#filetype=pdf
# counting the 'filetype' files
echo -n "number of $filetype files in the current directory tree: "
find -type f -name "*.$filetype" -ls|sed 's#.* \./##'|wc -l
echo -n "number of $filetype symbolic links in the current directory tree: "
find -type l -name "*.$filetype" -ls|sed 's#.* \./##'|wc -l
echo -n "number of $filetype normal files in the current directory tree: "
find -type f -name "*.$filetype" -ls|sed 's#.* \./##'|wc -l
echo -n "number of $filetype symbolic links in the current directory tree including linked directories: "
find -L -type f -name "*.$filetype" -ls 2> /tmp/c-counter |sed 's#.* \./##' | wc -l; cat /tmp/c-counter; rm /tmp/c-counter
# list directories with and without 'filetype' files (good for manual checking; comment away after test)
echo '---------- list directories:'
find -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)' || echo '{} empty'" \;
echo ''
#find -L -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)' || echo '{} empty'" \;
# count directories containing 'filetype' files
echo -n "number of directories with $filetype files: "
find -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)'" \;|grep 'contains file(s)$'|wc -l
# list and count directories including symbolic links, containing 'filetype' files
echo '---------- list all directories including symbolic links:'
find -L -type d -exec bash -c "ls -AF '{}' |grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)' || echo '{} empty'" \;
echo ''
echo -n "number of directories (including symbolic links) with $filetype files: "
find -L -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)'" \; 2>/dev/null |grep 'contains file(s)$'|wc -l
# count directories without 'filetype' files (good for checking; comment away after test)
echo -n "number of directories without $filetype files: "
find -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null || echo '{} empty'" \;|grep 'empty$'|wc -l
Из короткого shellscript:
$ ./ccntr
29 7
Из подробного shellscript:
$ LANG=C ./c-counter
number of c files in the current directory tree: 29
number of c symbolic links in the current directory tree: 1
number of c normal files in the current directory tree: 29
number of c symbolic links in the current directory tree including linked directories: 42
find: './cfiles/2/2': Too many levels of symbolic links
find: './cfiles/dirlink/2': Too many levels of symbolic links
---------- list directories:
. empty
./cfiles contains file(s)
./cfiles/2 contains file(s)
./cfiles/2/b contains file(s)
./cfiles/2/a contains file(s)
./cfiles/3 empty
./cfiles/3/b contains file(s)
./cfiles/3/a empty
./cfiles/1 contains file(s)
./cfiles/1/b empty
./cfiles/1/a empty
./cfiles/space d contains file(s)
number of directories with c files: 7
---------- list all directories including symbolic links:
. empty
./cfiles contains file(s)
./cfiles/2 contains file(s)
find: './cfiles/2/2': Too many levels of symbolic links
./cfiles/2/b contains file(s)
./cfiles/2/a contains file(s)
./cfiles/3 empty
./cfiles/3/b contains file(s)
./cfiles/3/a empty
./cfiles/dirlink empty
find: './cfiles/dirlink/2': Too many levels of symbolic links
./cfiles/dirlink/b contains file(s)
./cfiles/dirlink/a contains file(s)
./cfiles/1 contains file(s)
./cfiles/1/b empty
./cfiles/1/a empty
./cfiles/space d contains file(s)
number of directories (including symbolic links) with c files: 9
number of directories without c files: 5
$
Простой Perl один лайнер:
perl -MFile::Find=find -le'find(sub{/\.c\z/ and -f and $c{$File::Find::dir}=++$c}, @ARGV); print 0 + keys %c, " $c"' dir1 dir2
Или проще с командой find:
find dir1 dir2 -type f -name '*.c' -printf '%h\0' | perl -l -0ne'$c{$_}=1}{print 0 + keys %c, " $."'
Если вам нравится играть в гольф и иметь последние (например, менее десятилетия) Perl:
perl -MFile::Find=find -E'find(sub{/\.c$/&&-f&&($c{$File::Find::dir}=++$c)},".");say 0+keys%c," $c"'
find -type f -name '*.c' -printf '%h\0'|perl -0nE'$c{$_}=1}{say 0+keys%c," $."'
Используйте команду locate, которая намного быстрее, чем команда find.
$ sudo updatedb # necessary if files in focus were added `cron` daily.
$ printf "Number Files: " && locate -0r "$PWD.*\.c$" | xargs -0 -I{} sh -c 'test ! -L "$1" && echo "regular file"' _ {} | wc -l && printf "Number Dirs.: " && locate -r "$PWD.*\.c$" | sed 's%/[^/]*$%/%' | uniq -cu | wc -l
Number Files: 29
Number Dirs.: 7
Спасибо Муру за его ответ, чтобы помочь мне путем удаления символических ссылок из количества файлов в Unix & amp; Ответ на Linux.
Спасибо Тердону за его ответ $PWD (не направленный на меня) в Unix & amp; Ответ на Linux .
$ cd /
$ sudo updatedb
$ printf "Number Files: " && locate -cr "$PWD.*\.c$"
Number Files: 3523
$ printf "Number Dirs.: " && locate -r "$PWD.*\.c$" | sed 's%/[^/]*$%/%' | uniq -c | wc -l
Number Dirs.: 648
sudo updatedb Обновить базу данных, используемую командой locate, если сегодня были созданы файлы .c или если вы удалили файлы .c сегодня. locate -cr "$PWD.*\.c$" найдите все .c файлы в текущем каталоге и его дочерние элементы ($PWD). Вместо того, чтобы печатать имена файлов и распечатывать счетчик с аргументом -c. Параметр r задает регулярное выражение вместо соответствия по умолчанию *pattern*, которое может дать слишком много результатов. [F20]. Найдите все *.c файлы в текущем каталоге и ниже. Удалите имя файла с sed, оставив только имя каталога. Подсчитайте количество файлов в каждом каталоге с помощью uniq -c. Подсчитайте количество каталогов с помощью wc -l. $ cd /usr/src
$ printf "Number Files: " && locate -cr "$PWD.*\.c$" && printf "Number Dirs.: " && locate -r "$PWD.*\.c$" | sed 's%/[^/]*$%/%' | uniq -c | wc -l
Number Files: 3430
Number Dirs.: 624
Обратите внимание, что количество файлов и количество каталогов изменились. Я полагаю, что все пользователи имеют каталог /usr/src и могут работать над командами с разными значениями в зависимости от количества установленных ядер.
Длинная форма включает время, чтобы вы может видеть, насколько быстрее locate закончилось find. Даже если вам нужно запустить sudo updatedb, он во много раз быстрее, чем один find /.
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/Downloads$ sudo time updatedb
0.58user 1.32system 0:03.94elapsed 48%CPU (0avgtext+0avgdata 7568maxresident)k
48inputs+131920outputs (1major+3562minor)pagefaults 0swaps
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/Downloads$ time (printf "Number Files: " && locate -cr $PWD".*\.c$")
Number Files: 3523
real 0m0.775s
user 0m0.766s
sys 0m0.012s
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/Downloads$ time (printf "Number Dirs.: " && locate -r $PWD".*\.c$" | sed 's%/[^/]*$%/%' | uniq -c | wc -l)
Number Dirs.: 648
real 0m0.778s
user 0m0.788s
sys 0m0.027s
───────────────────────────────────────────────────────────────────────────────────────────
Примечание. Это все файлы на ВСЕ приводах и разделах. т.е. мы можем также искать команды Windows:
$ time (printf "Number Files: " && locate *.exe -c)
Number Files: 6541
real 0m0.946s
user 0m0.761s
sys 0m0.060s
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/Downloads$ time (printf "Number Dirs.: " && locate *.exe | sed 's%/[^/]*$%/%' | uniq -c | wc -l)
Number Dirs.: 3394
real 0m0.942s
user 0m0.803s
sys 0m0.092s
У меня есть три раздела Windows NT NTFS, автоматически смонтированные в /etc/fstab.
$ time (printf "Number Files: " && locate / -c && printf "Number Dirs.: " && locate / | sed 's%/[^/]*$%/%' | uniq -c | wc -l)
Number Files: 1637135
Number Dirs.: 286705
real 0m15.460s
user 0m13.471s
sys 0m2.786s
Требуется 15 секунд, чтобы посчитать 1637135 файлов в 286 705 каталогах. YMMV.
Для детальной разбивки на обработку регулярных выражений команды locate (кажется, не требуется в этом Q & amp; A, но используется на всякий случай), пожалуйста, прочтите следующее: Используйте " locate " в каком-то конкретном каталоге?
Дополнительная информация из последних статей:
sudo updatedb Обновить базу данных, используемую командой locate, если файлы .c были созданы сегодня или если вы HowtoForge - Linux Найдите команду для начинающих (8 примеров) locate -cr "$PWD.*\.c$" найдите все .c файлы в текущем каталоге и его дочерние элементы ($PWD). Вместо того, чтобы печатать имена файлов и распечатывать счетчик с аргументом -c. Параметр r задает регулярное выражение вместо соответствия по умолчанию *pattern*, которое может дать слишком много результатов.Вот мое предложение:
#!/bin/bash
tempfile=$(mktemp)
find -type f -name "*.c" -prune >$tempfile
grep -c / $tempfile
sed 's_[^/]*$__' $tempfile | sort -u | grep -c /
Этот короткий скрипт создает временный файл, находит каждый файл в и под текущим каталогом, заканчивающимся на .c, и записывает список в файл temp. grep затем используется для подсчета файлов (следуя Как я могу получить количество файлов в каталоге с помощью командной строки?) дважды: во второй раз каталоги, которые перечислены несколько раз, удаляются с помощью sort -u после удаления файлов из каждой строки, используя sed.
Это также корректно работает с новыми строками в именах файлов: grep -c / подсчитывает только строки с косой чертой и поэтому учитывает только первую строку многострочного имени файла в списке.
$ tree
.
├── 1
│ ├── 1
│ │ ├── test2.c
│ │ └── test.c
│ └── 2
│ └── test.c
└── 2
├── 1
│ └── test.c
└── 2
$ tempfile=$(mktemp);find -type f -name "*.c" -prune >$tempfile;grep -c / $tempfile;sed 's_[^/]*$__' $tempfile | sort -u | grep -c /
4
3
Python имеет os.walk, что делает такие задачи такими же легкими, интуитивно понятными и автоматически надежными даже перед лицом странных имен файлов, таких как те, которые содержат символы новой строки. Этот сценарий Python 3, который я изначально разместил в чате, предназначен для запуска в текущем каталоге (но он не должен находиться в текущем каталоге, и вы можете изменить его путь к os.walk), :
#!/usr/bin/env python3
import os
dc = fc = 0
for _, _, fs in os.walk('.'):
c = sum(f.endswith('.c') for f in fs)
if c:
dc += 1
fc += c
print(dc, fc)
Это печатает количество каталогов, в которых содержится хотя бы один файл, имя которого заканчивается на .c, за которым следует пробел, за которым следует количество файлов, имена которых заканчиваются на .c , «Скрытые» файлы, то есть файлы, имена которых начинаются с ., включены, а скрытые каталоги аналогичным образом пересекаются.
os.walk Он перечисляет все каталоги, которые рекурсивно доступны из исходной точки, которую вы им даете, приводя информацию о каждом из них как кортеж из трех значений root, dirs, files. Для каждого каталога он переходит к (включая первый, имя которого вы даете ему):
root содержит путь к этому каталогу. Обратите внимание, что это абсолютно не связано с «корневым каталогом» системы / (а также не связано с /root), хотя оно будет идти к тем, если вы начнете там. В этом случае root начинается с пути . - i.e., Текущего каталога - и проходит повсюду под ним. dirs содержит список путей всех подкаталогов каталога, имя которого в настоящее время хранится в root. files содержит список путей всех файлов, которые находятся в каталоге, имя которого в настоящее время хранится в root, но которые не являются самими каталогами. Обратите внимание, что это включает в себя другие типы файлов, чем обычные файлы, включая символические ссылки, но похоже, что вы не ожидаете окончания таких записей в .c и заинтересованы в том, чтобы видеть что-либо подобное.В этом случае мне нужно только изучить третий элемент кортежа, files (который я называю fs в скрипте). Как и команда find, Python os.walk перемещается в подкаталоги для меня; единственное, что я должен проверить сам, это имена файлов, в которые каждый из них содержится. В отличие от команды find, os.walk автоматически предоставляет мне список этих имен файлов.
Этот скрипт не соответствует символическим ссылкам. Вы, вероятно, , что хотите, чтобы для такой операции были использованы символические ссылки, потому что они могли образовывать циклы, и поскольку даже если нет циклов, одни и те же файлы и каталоги могут проходить и подсчитываться несколько раз, если они доступны через различные символические ссылки.
Если вы когда-либо хотели os.walk следовать символическим ссылкам, что вы обычно не хотели, то вы можете передать followlinks=true на него. То есть вместо записи os.walk('.') вы можете написать os.walk('.', followlinks=true). Я повторяю, что вы редко этого хотели, особенно для такой задачи, в которой вы рекурсивно перечисляете всю структуру каталогов, независимо от того, насколько она велика, и подсчитывая все файлы в ней, которые удовлетворяют некоторым требованиям.
Простой Perl один лайнер:
perl -MFile::Find=find -le'find(sub{/\.c\z/ and -f and $c{$File::Find::dir}=++$c}, @ARGV); print 0 + keys %c, " $c"' dir1 dir2
Или проще с командой find:
find dir1 dir2 -type f -name '*.c' -printf '%h\0' | perl -l -0ne'$c{$_}=1}{print 0 + keys %c, " $."'
Если вам нравится играть в гольф и иметь последние (например, менее десятилетия) Perl:
perl -MFile::Find=find -E'find(sub{/\.c$/&&-f&&($c{$File::Find::dir}=++$c)},".");say 0+keys%c," $c"'
find -type f -name '*.c' -printf '%h\0'|perl -0nE'$c{$_}=1}{say 0+keys%c," $."'
Я предлагаю небольшой командный столбец bash с двумя основными командами (и переменной filetype, чтобы было легко переключиться, чтобы искать другие типы файлов).
Он не ищет или в символических ссылках, только обычные файлы.
#!/bin/bash
filetype=c
#filetype=pdf
# count the 'filetype' files
find -type f -name "*.$filetype" -ls|sed 's#.* \./##'|wc -l | tr '\n' ' '
# count directories containing 'filetype' files
find -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)'" \;|grep 'contains file(s)$'|wc -l
Это более подробная версия, которая также рассматривает символические ссылки,
#!/bin/bash
filetype=c
#filetype=pdf
# counting the 'filetype' files
echo -n "number of $filetype files in the current directory tree: "
find -type f -name "*.$filetype" -ls|sed 's#.* \./##'|wc -l
echo -n "number of $filetype symbolic links in the current directory tree: "
find -type l -name "*.$filetype" -ls|sed 's#.* \./##'|wc -l
echo -n "number of $filetype normal files in the current directory tree: "
find -type f -name "*.$filetype" -ls|sed 's#.* \./##'|wc -l
echo -n "number of $filetype symbolic links in the current directory tree including linked directories: "
find -L -type f -name "*.$filetype" -ls 2> /tmp/c-counter |sed 's#.* \./##' | wc -l; cat /tmp/c-counter; rm /tmp/c-counter
# list directories with and without 'filetype' files (good for manual checking; comment away after test)
echo '---------- list directories:'
find -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)' || echo '{} empty'" \;
echo ''
#find -L -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)' || echo '{} empty'" \;
# count directories containing 'filetype' files
echo -n "number of directories with $filetype files: "
find -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)'" \;|grep 'contains file(s)$'|wc -l
# list and count directories including symbolic links, containing 'filetype' files
echo '---------- list all directories including symbolic links:'
find -L -type d -exec bash -c "ls -AF '{}' |grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)' || echo '{} empty'" \;
echo ''
echo -n "number of directories (including symbolic links) with $filetype files: "
find -L -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)'" \; 2>/dev/null |grep 'contains file(s)$'|wc -l
# count directories without 'filetype' files (good for checking; comment away after test)
echo -n "number of directories without $filetype files: "
find -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null || echo '{} empty'" \;|grep 'empty$'|wc -l
Из короткого shellscript:
$ ./ccntr
29 7
Из подробного shellscript:
$ LANG=C ./c-counter
number of c files in the current directory tree: 29
number of c symbolic links in the current directory tree: 1
number of c normal files in the current directory tree: 29
number of c symbolic links in the current directory tree including linked directories: 42
find: './cfiles/2/2': Too many levels of symbolic links
find: './cfiles/dirlink/2': Too many levels of symbolic links
---------- list directories:
. empty
./cfiles contains file(s)
./cfiles/2 contains file(s)
./cfiles/2/b contains file(s)
./cfiles/2/a contains file(s)
./cfiles/3 empty
./cfiles/3/b contains file(s)
./cfiles/3/a empty
./cfiles/1 contains file(s)
./cfiles/1/b empty
./cfiles/1/a empty
./cfiles/space d contains file(s)
number of directories with c files: 7
---------- list all directories including symbolic links:
. empty
./cfiles contains file(s)
./cfiles/2 contains file(s)
find: './cfiles/2/2': Too many levels of symbolic links
./cfiles/2/b contains file(s)
./cfiles/2/a contains file(s)
./cfiles/3 empty
./cfiles/3/b contains file(s)
./cfiles/3/a empty
./cfiles/dirlink empty
find: './cfiles/dirlink/2': Too many levels of symbolic links
./cfiles/dirlink/b contains file(s)
./cfiles/dirlink/a contains file(s)
./cfiles/1 contains file(s)
./cfiles/1/b empty
./cfiles/1/a empty
./cfiles/space d contains file(s)
number of directories (including symbolic links) with c files: 9
number of directories without c files: 5
$
Найти + Perl:
$ find . -type f -iname '*.c' -printf '%h\0' |
perl -0 -ne '$k{$_}++; }{ print scalar keys %k, " $.\n" '
7 29
Команда find найдет любые обычные файлы (так что никаких символических ссылок или каталогов), а затем напечатать имя каталога, которое они находятся в (%h), а затем \0.
perl -0 -ne: прочитайте ввод строки за строкой (-n) и примените скрипт, заданный -e для каждой строки. [F9] устанавливает разделитель входных строк на \0, чтобы мы могли считывать ввод с нулевым ограничением. $k{$_}++: $_ - специальная переменная, которая принимает значение текущей строки. Это используется как ключ к хешу %k, значения которого представляют собой количество раз, когда была видна каждая строка ввода (имя каталога). }{: это сокращенный способ написания END{}. Любые команды после }{ будут выполняться один раз, после того, как все данные будут обработаны. print scalar keys %k, " $.\n": keys %k возвращает массив ключей в хеше %k. scalar keys %k дает количество элементов в этом массиве, количество просмотренных каталогов. Это печатается вместе с текущим значением $., специальной переменной, которая содержит текущий номер строки ввода. Так как это выполняется в конце, текущий номер строки ввода будет номером последней строки, поэтому количество строк, видимых до сих пор.Вы можете расширить команду perl для этого, для ясности:
find . -type f -iname '*.c' -printf '%h\0' |
perl -0 -e 'while($line = <STDIN>){
$dirs{$line}++;
$tot++;
}
$count = scalar keys %dirs;
print "$count $tot\n" '
Используйте команду locate, которая намного быстрее, чем команда find.
$ sudo updatedb # necessary if files in focus were added `cron` daily.
$ printf "Number Files: " && locate -0r "$PWD.*\.c$" | xargs -0 -I{} sh -c 'test ! -L "$1" && echo "regular file"' _ {} | wc -l && printf "Number Dirs.: " && locate -r "$PWD.*\.c$" | sed 's%/[^/]*$%/%' | uniq -cu | wc -l
Number Files: 29
Number Dirs.: 7
Спасибо Муру за его ответ, чтобы помочь мне путем удаления символических ссылок из количества файлов в Unix & amp; Ответ на Linux.
Спасибо Тердону за его ответ $PWD (не направленный на меня) в Unix & amp; Ответ на Linux .
$ cd /
$ sudo updatedb
$ printf "Number Files: " && locate -cr "$PWD.*\.c$"
Number Files: 3523
$ printf "Number Dirs.: " && locate -r "$PWD.*\.c$" | sed 's%/[^/]*$%/%' | uniq -c | wc -l
Number Dirs.: 648
sudo updatedb Обновить базу данных, используемую командой locate, если сегодня были созданы файлы .c или если вы удалили файлы .c сегодня. locate -cr "$PWD.*\.c$" найдите все .c файлы в текущем каталоге и его дочерние элементы ($PWD). Вместо того, чтобы печатать имена файлов и распечатывать счетчик с аргументом -c. Параметр r задает регулярное выражение вместо соответствия по умолчанию *pattern*, которое может дать слишком много результатов. [F20]. Найдите все *.c файлы в текущем каталоге и ниже. Удалите имя файла с sed, оставив только имя каталога. Подсчитайте количество файлов в каждом каталоге с помощью uniq -c. Подсчитайте количество каталогов с помощью wc -l. $ cd /usr/src
$ printf "Number Files: " && locate -cr "$PWD.*\.c$" && printf "Number Dirs.: " && locate -r "$PWD.*\.c$" | sed 's%/[^/]*$%/%' | uniq -c | wc -l
Number Files: 3430
Number Dirs.: 624
Обратите внимание, что количество файлов и количество каталогов изменились. Я полагаю, что все пользователи имеют каталог /usr/src и могут работать над командами с разными значениями в зависимости от количества установленных ядер.
Длинная форма включает время, чтобы вы может видеть, насколько быстрее locate закончилось find. Даже если вам нужно запустить sudo updatedb, он во много раз быстрее, чем один find /.
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/Downloads$ sudo time updatedb
0.58user 1.32system 0:03.94elapsed 48%CPU (0avgtext+0avgdata 7568maxresident)k
48inputs+131920outputs (1major+3562minor)pagefaults 0swaps
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/Downloads$ time (printf "Number Files: " && locate -cr $PWD".*\.c$")
Number Files: 3523
real 0m0.775s
user 0m0.766s
sys 0m0.012s
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/Downloads$ time (printf "Number Dirs.: " && locate -r $PWD".*\.c$" | sed 's%/[^/]*$%/%' | uniq -c | wc -l)
Number Dirs.: 648
real 0m0.778s
user 0m0.788s
sys 0m0.027s
───────────────────────────────────────────────────────────────────────────────────────────
Примечание. Это все файлы на ВСЕ приводах и разделах. т.е. мы можем также искать команды Windows:
$ time (printf "Number Files: " && locate *.exe -c)
Number Files: 6541
real 0m0.946s
user 0m0.761s
sys 0m0.060s
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/Downloads$ time (printf "Number Dirs.: " && locate *.exe | sed 's%/[^/]*$%/%' | uniq -c | wc -l)
Number Dirs.: 3394
real 0m0.942s
user 0m0.803s
sys 0m0.092s
У меня есть три раздела Windows NT NTFS, автоматически смонтированные в /etc/fstab.
$ time (printf "Number Files: " && locate / -c && printf "Number Dirs.: " && locate / | sed 's%/[^/]*$%/%' | uniq -c | wc -l)
Number Files: 1637135
Number Dirs.: 286705
real 0m15.460s
user 0m13.471s
sys 0m2.786s
Требуется 15 секунд, чтобы посчитать 1637135 файлов в 286 705 каталогах. YMMV.
Для детальной разбивки на обработку регулярных выражений команды locate (кажется, не требуется в этом Q & amp; A, но используется на всякий случай), пожалуйста, прочтите следующее: Используйте & quot; locate & quot; в каком-то конкретном каталоге?
Дополнительная информация из последних статей:
sudo updatedb Обновить базу данных, используемую командой locate, если файлы .c были созданы сегодня или если вы HowtoForge - Linux Найдите команду для начинающих (8 примеров) locate -cr "$PWD.*\.c$" найдите все .c файлы в текущем каталоге и его дочерние элементы ($PWD). Вместо того, чтобы печатать имена файлов и распечатывать счетчик с аргументом -c. Параметр r задает регулярное выражение вместо соответствия по умолчанию *pattern*, которое может дать слишком много результатов.Вот мое предложение:
#!/bin/bash
tempfile=$(mktemp)
find -type f -name "*.c" -prune >$tempfile
grep -c / $tempfile
sed 's_[^/]*$__' $tempfile | sort -u | grep -c /
Этот короткий скрипт создает временный файл, находит каждый файл в и под текущим каталогом, заканчивающимся на .c, и записывает список в файл temp. grep затем используется для подсчета файлов (следуя Как я могу получить количество файлов в каталоге с помощью командной строки?) дважды: во второй раз каталоги, которые перечислены несколько раз, удаляются с помощью sort -u после удаления файлов из каждой строки, используя sed.
Это также корректно работает с новыми строками в именах файлов: grep -c / подсчитывает только строки с косой чертой и поэтому учитывает только первую строку многострочного имени файла в списке.
$ tree
.
├── 1
│ ├── 1
│ │ ├── test2.c
│ │ └── test.c
│ └── 2
│ └── test.c
└── 2
├── 1
│ └── test.c
└── 2
$ tempfile=$(mktemp);find -type f -name "*.c" -prune >$tempfile;grep -c / $tempfile;sed 's_[^/]*$__' $tempfile | sort -u | grep -c /
4
3
Python имеет os.walk, что делает такие задачи такими же легкими, интуитивно понятными и автоматически надежными даже перед лицом странных имен файлов, таких как те, которые содержат символы новой строки. Этот сценарий Python 3, который я изначально разместил в чате, предназначен для запуска в текущем каталоге (но он не должен находиться в текущем каталоге, и вы можете изменить его путь к os.walk), :
#!/usr/bin/env python3
import os
dc = fc = 0
for _, _, fs in os.walk('.'):
c = sum(f.endswith('.c') for f in fs)
if c:
dc += 1
fc += c
print(dc, fc)
Это печатает количество каталогов, в которых содержится хотя бы один файл, имя которого заканчивается на .c, за которым следует пробел, за которым следует количество файлов, имена которых заканчиваются на .c , «Скрытые» файлы, то есть файлы, имена которых начинаются с ., включены, а скрытые каталоги аналогичным образом пересекаются.
os.walk Он перечисляет все каталоги, которые рекурсивно доступны из исходной точки, которую вы им даете, приводя информацию о каждом из них как кортеж из трех значений root, dirs, files. Для каждого каталога он переходит к (включая первый, имя которого вы даете ему):
root содержит путь к этому каталогу. Обратите внимание, что это абсолютно не связано с «корневым каталогом» системы / (а также не связано с /root), хотя оно будет идти к тем, если вы начнете там. В этом случае root начинается с пути . - i.e., Текущего каталога - и проходит повсюду под ним. dirs содержит список путей всех подкаталогов каталога, имя которого в настоящее время хранится в root. files содержит список путей всех файлов, которые находятся в каталоге, имя которого в настоящее время хранится в root, но которые не являются самими каталогами. Обратите внимание, что это включает в себя другие типы файлов, чем обычные файлы, включая символические ссылки, но похоже, что вы не ожидаете окончания таких записей в .c и заинтересованы в том, чтобы видеть что-либо подобное.В этом случае мне нужно только изучить третий элемент кортежа, files (который я называю fs в скрипте). Как и команда find, Python os.walk перемещается в подкаталоги для меня; единственное, что я должен проверить сам, это имена файлов, в которые каждый из них содержится. В отличие от команды find, os.walk автоматически предоставляет мне список этих имен файлов.
Этот скрипт не соответствует символическим ссылкам. Вы, вероятно, , что хотите, чтобы для такой операции были использованы символические ссылки, потому что они могли образовывать циклы, и поскольку даже если нет циклов, одни и те же файлы и каталоги могут проходить и подсчитываться несколько раз, если они доступны через различные символические ссылки.
Если вы когда-либо хотели os.walk следовать символическим ссылкам, что вы обычно не хотели, то вы можете передать followlinks=true на него. То есть вместо записи os.walk('.') вы можете написать os.walk('.', followlinks=true). Я повторяю, что вы редко этого хотели, особенно для такой задачи, в которой вы рекурсивно перечисляете всю структуру каталогов, независимо от того, насколько она велика, и подсчитывая все файлы в ней, которые удовлетворяют некоторым требованиям.
Простой Perl один лайнер:
perl -MFile::Find=find -le'find(sub{/\.c\z/ and -f and $c{$File::Find::dir}=++$c}, @ARGV); print 0 + keys %c, " $c"' dir1 dir2
Или проще с командой find:
find dir1 dir2 -type f -name '*.c' -printf '%h\0' | perl -l -0ne'$c{$_}=1}{print 0 + keys %c, " $."'
Если вам нравится играть в гольф и иметь последние (например, менее десятилетия) Perl:
perl -MFile::Find=find -E'find(sub{/\.c$/&&-f&&($c{$File::Find::dir}=++$c)},".");say 0+keys%c," $c"'
find -type f -name '*.c' -printf '%h\0'|perl -0nE'$c{$_}=1}{say 0+keys%c," $."'
Я предлагаю небольшой командный столбец bash с двумя основными командами (и переменной filetype, чтобы было легко переключиться, чтобы искать другие типы файлов).
Он не ищет или в символических ссылках, только обычные файлы.
#!/bin/bash
filetype=c
#filetype=pdf
# count the 'filetype' files
find -type f -name "*.$filetype" -ls|sed 's#.* \./##'|wc -l | tr '\n' ' '
# count directories containing 'filetype' files
find -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)'" \;|grep 'contains file(s)$'|wc -l
Это более подробная версия, которая также рассматривает символические ссылки,
#!/bin/bash
filetype=c
#filetype=pdf
# counting the 'filetype' files
echo -n "number of $filetype files in the current directory tree: "
find -type f -name "*.$filetype" -ls|sed 's#.* \./##'|wc -l
echo -n "number of $filetype symbolic links in the current directory tree: "
find -type l -name "*.$filetype" -ls|sed 's#.* \./##'|wc -l
echo -n "number of $filetype normal files in the current directory tree: "
find -type f -name "*.$filetype" -ls|sed 's#.* \./##'|wc -l
echo -n "number of $filetype symbolic links in the current directory tree including linked directories: "
find -L -type f -name "*.$filetype" -ls 2> /tmp/c-counter |sed 's#.* \./##' | wc -l; cat /tmp/c-counter; rm /tmp/c-counter
# list directories with and without 'filetype' files (good for manual checking; comment away after test)
echo '---------- list directories:'
find -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)' || echo '{} empty'" \;
echo ''
#find -L -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)' || echo '{} empty'" \;
# count directories containing 'filetype' files
echo -n "number of directories with $filetype files: "
find -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)'" \;|grep 'contains file(s)$'|wc -l
# list and count directories including symbolic links, containing 'filetype' files
echo '---------- list all directories including symbolic links:'
find -L -type d -exec bash -c "ls -AF '{}' |grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)' || echo '{} empty'" \;
echo ''
echo -n "number of directories (including symbolic links) with $filetype files: "
find -L -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)'" \; 2>/dev/null |grep 'contains file(s)$'|wc -l
# count directories without 'filetype' files (good for checking; comment away after test)
echo -n "number of directories without $filetype files: "
find -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null || echo '{} empty'" \;|grep 'empty$'|wc -l
Из короткого shellscript:
$ ./ccntr
29 7
Из подробного shellscript:
$ LANG=C ./c-counter
number of c files in the current directory tree: 29
number of c symbolic links in the current directory tree: 1
number of c normal files in the current directory tree: 29
number of c symbolic links in the current directory tree including linked directories: 42
find: './cfiles/2/2': Too many levels of symbolic links
find: './cfiles/dirlink/2': Too many levels of symbolic links
---------- list directories:
. empty
./cfiles contains file(s)
./cfiles/2 contains file(s)
./cfiles/2/b contains file(s)
./cfiles/2/a contains file(s)
./cfiles/3 empty
./cfiles/3/b contains file(s)
./cfiles/3/a empty
./cfiles/1 contains file(s)
./cfiles/1/b empty
./cfiles/1/a empty
./cfiles/space d contains file(s)
number of directories with c files: 7
---------- list all directories including symbolic links:
. empty
./cfiles contains file(s)
./cfiles/2 contains file(s)
find: './cfiles/2/2': Too many levels of symbolic links
./cfiles/2/b contains file(s)
./cfiles/2/a contains file(s)
./cfiles/3 empty
./cfiles/3/b contains file(s)
./cfiles/3/a empty
./cfiles/dirlink empty
find: './cfiles/dirlink/2': Too many levels of symbolic links
./cfiles/dirlink/b contains file(s)
./cfiles/dirlink/a contains file(s)
./cfiles/1 contains file(s)
./cfiles/1/b empty
./cfiles/1/a empty
./cfiles/space d contains file(s)
number of directories (including symbolic links) with c files: 9
number of directories without c files: 5
$
Найти + Perl:
$ find . -type f -iname '*.c' -printf '%h\0' |
perl -0 -ne '$k{$_}++; }{ print scalar keys %k, " $.\n" '
7 29
Команда find найдет любые обычные файлы (так что никаких символических ссылок или каталогов), а затем напечатать имя каталога, которое они находятся в (%h), а затем \0.
perl -0 -ne: прочитайте ввод строки за строкой (-n) и примените скрипт, заданный -e для каждой строки. [F9] устанавливает разделитель входных строк на \0, чтобы мы могли считывать ввод с нулевым ограничением. $k{$_}++: $_ - специальная переменная, которая принимает значение текущей строки. Это используется как ключ к хешу %k, значения которого представляют собой количество раз, когда была видна каждая строка ввода (имя каталога). }{: это сокращенный способ написания END{}. Любые команды после }{ будут выполняться один раз, после того, как все данные будут обработаны. print scalar keys %k, " $.\n": keys %k возвращает массив ключей в хеше %k. scalar keys %k дает количество элементов в этом массиве, количество просмотренных каталогов. Это печатается вместе с текущим значением $., специальной переменной, которая содержит текущий номер строки ввода. Так как это выполняется в конце, текущий номер строки ввода будет номером последней строки, поэтому количество строк, видимых до сих пор.Вы можете расширить команду perl для этого, для ясности:
find . -type f -iname '*.c' -printf '%h\0' |
perl -0 -e 'while($line = <STDIN>){
$dirs{$line}++;
$tot++;
}
$count = scalar keys %dirs;
print "$count $tot\n" '
Используйте команду locate, которая намного быстрее, чем команда find.
$ sudo updatedb # necessary if files in focus were added `cron` daily.
$ printf "Number Files: " && locate -0r "$PWD.*\.c$" | xargs -0 -I{} sh -c 'test ! -L "$1" && echo "regular file"' _ {} | wc -l && printf "Number Dirs.: " && locate -r "$PWD.*\.c$" | sed 's%/[^/]*$%/%' | uniq -cu | wc -l
Number Files: 29
Number Dirs.: 7
Спасибо Муру за его ответ, чтобы помочь мне путем удаления символических ссылок из количества файлов в Unix & amp; Ответ на Linux.
Спасибо Тердону за его ответ $PWD (не направленный на меня) в Unix & amp; Ответ на Linux .
$ cd /
$ sudo updatedb
$ printf "Number Files: " && locate -cr "$PWD.*\.c$"
Number Files: 3523
$ printf "Number Dirs.: " && locate -r "$PWD.*\.c$" | sed 's%/[^/]*$%/%' | uniq -c | wc -l
Number Dirs.: 648
sudo updatedb Обновить базу данных, используемую командой locate, если сегодня были созданы файлы .c или если вы удалили файлы .c сегодня. locate -cr "$PWD.*\.c$" найдите все .c файлы в текущем каталоге и его дочерние элементы ($PWD). Вместо того, чтобы печатать имена файлов и распечатывать счетчик с аргументом -c. Параметр r задает регулярное выражение вместо соответствия по умолчанию *pattern*, которое может дать слишком много результатов. [F20]. Найдите все *.c файлы в текущем каталоге и ниже. Удалите имя файла с sed, оставив только имя каталога. Подсчитайте количество файлов в каждом каталоге с помощью uniq -c. Подсчитайте количество каталогов с помощью wc -l. $ cd /usr/src
$ printf "Number Files: " && locate -cr "$PWD.*\.c$" && printf "Number Dirs.: " && locate -r "$PWD.*\.c$" | sed 's%/[^/]*$%/%' | uniq -c | wc -l
Number Files: 3430
Number Dirs.: 624
Обратите внимание, что количество файлов и количество каталогов изменились. Я полагаю, что все пользователи имеют каталог /usr/src и могут работать над командами с разными значениями в зависимости от количества установленных ядер.
Длинная форма включает время, чтобы вы может видеть, насколько быстрее locate закончилось find. Даже если вам нужно запустить sudo updatedb, он во много раз быстрее, чем один find /.
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/Downloads$ sudo time updatedb
0.58user 1.32system 0:03.94elapsed 48%CPU (0avgtext+0avgdata 7568maxresident)k
48inputs+131920outputs (1major+3562minor)pagefaults 0swaps
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/Downloads$ time (printf "Number Files: " && locate -cr $PWD".*\.c$")
Number Files: 3523
real 0m0.775s
user 0m0.766s
sys 0m0.012s
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/Downloads$ time (printf "Number Dirs.: " && locate -r $PWD".*\.c$" | sed 's%/[^/]*$%/%' | uniq -c | wc -l)
Number Dirs.: 648
real 0m0.778s
user 0m0.788s
sys 0m0.027s
───────────────────────────────────────────────────────────────────────────────────────────
Примечание. Это все файлы на ВСЕ приводах и разделах. т.е. мы можем также искать команды Windows:
$ time (printf "Number Files: " && locate *.exe -c)
Number Files: 6541
real 0m0.946s
user 0m0.761s
sys 0m0.060s
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/Downloads$ time (printf "Number Dirs.: " && locate *.exe | sed 's%/[^/]*$%/%' | uniq -c | wc -l)
Number Dirs.: 3394
real 0m0.942s
user 0m0.803s
sys 0m0.092s
У меня есть три раздела Windows NT NTFS, автоматически смонтированные в /etc/fstab.
$ time (printf "Number Files: " && locate / -c && printf "Number Dirs.: " && locate / | sed 's%/[^/]*$%/%' | uniq -c | wc -l)
Number Files: 1637135
Number Dirs.: 286705
real 0m15.460s
user 0m13.471s
sys 0m2.786s
Требуется 15 секунд, чтобы посчитать 1637135 файлов в 286 705 каталогах. YMMV.
Для детальной разбивки на обработку регулярных выражений команды locate (кажется, не требуется в этом Q & amp; A, но используется на всякий случай), пожалуйста, прочтите следующее: Используйте & quot; locate & quot; в каком-то конкретном каталоге?
Дополнительная информация из последних статей:
sudo updatedb Обновить базу данных, используемую командой locate, если файлы .c были созданы сегодня или если вы HowtoForge - Linux Найдите команду для начинающих (8 примеров) locate -cr "$PWD.*\.c$" найдите все .c файлы в текущем каталоге и его дочерние элементы ($PWD). Вместо того, чтобы печатать имена файлов и распечатывать счетчик с аргументом -c. Параметр r задает регулярное выражение вместо соответствия по умолчанию *pattern*, которое может дать слишком много результатов.