Resposta curta:
\ls -afq | wc -l
(Isso inclui .
e ..
, então subtraia 2.)
Quando você lista os arquivos em um diretório, três coisas comuns podem acontecer:
- Enumerando os nomes dos arquivos no diretório. Isso é inescapável: não há como contar os arquivos em um diretório sem enumerá-los.
- Classificando os nomes dos arquivos. Os curingas da shell e o comando
ls
fazem isso. - Chamando
stat
para recuperar metadados sobre cada entrada de diretório, como, por exemplo, se é um diretório.
# 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 de maneira compacta em alguns blocos. # 2 desperdiça algum tempo de CPU, mas muitas vezes não é um disjuntor de negócio.
Se não houver novas linhas em nomes de arquivos, um simples ls -A | wc -l
informará quantos arquivos existem no diretório. Tenha em atenção que, se tiver um alias para ls
, pode desencadear uma chamada para stat
(por exemplo, ls --color
ou ls -F
precisa de saber o tipo de ficheiro, o que requer uma chamada para stat
). linha de comando, chame command ls -A | wc -l
ou \ls -A | wc -l
para evitar um alias.
Se houver novas linhas no nome do arquivo, se as novas linhas são listadas ou não, depende da variante Unix. GNU coreutils e BusyBox assumem o padrão de exibir ?
para uma nova linha, então eles são seguros.
Chame ls -f
para listar as entradas sem classificá-las (# 2). Isso ativa automaticamente -a
(pelo menos em sistemas modernos). A opção -f
está em POSIX, mas com status opcional; a maioria das implementações suportam, 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 do BusyBox às custas de arquivos de contagem excessiva cujo nome contém um caractere de nova linha.
Se o diretório não tiver subdiretórios, a maioria das versões de find
não chamará stat
em suas entradas (otimização do diretório folha: um diretório com uma contagem de links de 2 não pode ter subdiretórios, portanto find
doesn ' Não é necessário pesquisar os metadados das entradas, a menos que uma condição como -type
exija isso. Portanto, find . | wc -l
é uma maneira rápida e portátil 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 tiver subdiretórios, mas os nomes dos arquivos contiverem novas linhas, tente um desses (o segundo deve ser mais rápido se for suportado, mas pode não ser notavelmente).
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: mesmo find . -maxdepth 1
chamadas stat
em cada entrada (pelo menos com o find do GNU find e BusyBox). Você evita a classificação (# 2), mas paga o preço de uma pesquisa de inode (# 3) que mata o desempenho.
No shell sem ferramentas externas, você pode executar a contagem dos arquivos no diretório atual com set -- *; echo $#
. Isso perde os arquivos de ponto (arquivos cujo nome começa com .
) e relata 1 em vez de 0 em um diretório vazio. Esta é a maneira mais rápida de contar arquivos em pequenos diretórios, porque não requer iniciar um programa externo, mas (exceto em zsh) desperdiça tempo para diretórios maiores devido à etapa de ordenação (# 2).
-
No bash, essa é 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, essa é uma maneira confiável de contar os arquivos no diretório atual:
a=(*(DNoN)) echo $#a
Se você tiver a opção
mark_dirs
definida, certifique-se de desativá-la:a=(*(DNoN^M))
. -
Em qualquer shell POSIX, essa é 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 one.