Resposta curta:
\ls -afq | wc -l
(Isso inclui .
e ..
, portanto, subtraia 2.)
Quando você lista os arquivos em um diretório, três coisas comuns podem acontecer:
- Enumerando os nomes de arquivo no diretório Isso é inevitável: não há como contar os arquivos em um diretório sem enumerá-los.
- Classificando os nomes dos arquivos. Os curingas do shell e o
ls
comando fazem isso.
- Chamando
stat
para recuperar metadados sobre cada entrada de diretório, como se é um diretório.
O número 3 é o mais caro, de longe, porque requer o carregamento de um inode para cada arquivo. Em comparação, todos os nomes de arquivos necessários para o nº 1 são armazenados compactamente em alguns blocos. O nº 2 desperdiça algum tempo de CPU, mas geralmente não é um disjuntor.
Se não houver novas linhas nos nomes dos arquivos, um simples ls -A | wc -l
informa quantos arquivos existem no diretório. Lembre-se de que, se você tiver um apelido para ls
, isso pode acionar uma chamada para stat
(por exemplo, ls --color
ou ls -F
precisar saber o tipo de arquivo, o qual requer uma chamada para stat
); portanto, na linha de comando, ligue command ls -A | wc -l
ou \ls -A | wc -l
para evitar um apelido.
Se houver novas linhas no nome do arquivo, se as novas linhas estão listadas ou não, depende da variante Unix. O coreutils GNU e o BusyBox assumem o padrão de exibição ?
para uma nova linha, para que sejam seguros.
Ligue ls -f
para listar as entradas sem classificá-las (nº 2). Isso é ativado automaticamente -a
(pelo menos nos sistemas modernos). A -f
opção está no POSIX, mas com status opcional; a maioria das implementações suporta, mas não o BusyBox. A opção -q
substitui caracteres não imprimíveis, incluindo novas linhas por ?
; é POSIX, mas não é suportado pelo BusyBox, portanto, omita-o se você precisar do suporte ao BusyBox às custas da contagem excessiva de arquivos cujo nome contém um caractere de nova linha.
Se o diretório não tiver subdiretórios, a maioria das versões find
não chamará stat
suas entradas (otimização de diretório em folha: um diretório com uma contagem de links 2 não pode ter subdiretórios, portanto, find
não é necessário procurar os metadados das entradas, a menos que condição -type
requerida). Assim, find . | wc -l
é uma maneira portátil e rápida de contar arquivos em um diretório, desde que o diretório não tenha subdiretórios e que nenhum nome de arquivo contenha uma nova linha.
Se o diretório não possuir subdiretórios, mas os nomes dos arquivos puderem conter novas linhas, tente um destes (o segundo deve ser mais rápido se for suportado, mas pode não ser notável).
find -print0 | tr -dc \\0 | wc -c
find -printf a | wc -c
Por outro lado, não use find
se o diretório tiver subdiretórios: inclusive find . -maxdepth 1
chama stat
cada entrada (pelo menos com o GNU find e BusyBox find). Você evita a classificação (nº 2), mas paga o preço de uma pesquisa de inode (nº 3) que reduz o desempenho.
No shell sem ferramentas externas, é possível executar a contagem dos arquivos no diretório atual com set -- *; echo $#
. Isso perde arquivos de ponto (arquivos cujo nome começa com .
) e informa 1 em vez de 0 em um diretório vazio. Essa é a maneira mais rápida de contar arquivos em diretórios pequenos, pois não requer o início de um programa externo, mas (exceto no zsh) perde tempo para diretórios maiores devido à etapa de classificação (# 2).
No bash, esta é uma maneira confiável de contar os arquivos no diretório atual:
shopt -s dotglob nullglob
a=(*)
echo ${#a[@]}
No ksh93, esta é uma maneira confiável de contar os arquivos no diretório atual:
FIGNORE='@(.|..)'
a=(~(N)*)
echo ${#a[@]}
No zsh, esta é uma maneira confiável de contar os arquivos no diretório atual:
a=(*(DNoN))
echo $#a
Se você tem o mark_dirs
conjunto de opção, certifique-se de desligá-lo: a=(*(DNoN^M))
.
Em qualquer shell POSIX, esta é uma maneira confiável de contar os arquivos no diretório atual:
total=0
set -- *
if [ $# -ne 1 ] || [ -e "$1" ] || [ -L "$1" ]; then total=$((total+$#)); fi
set -- .[!.]*
if [ $# -ne 1 ] || [ -e "$1" ] || [ -L "$1" ]; then total=$((total+$#)); fi
set -- ..?*
if [ $# -ne 1 ] || [ -e "$1" ] || [ -L "$1" ]; then total=$((total+$#)); fi
echo "$total"
Todos esses métodos classificam os nomes dos arquivos, exceto o zsh.
ls -l|wc -l
seria desligado por uma devido ao total de blocos na primeira linha dels -l
saída