O que 12você vê não é o número de arquivos, mas o número de blocos de disco consumidos.
De info coreutils 'ls invocation':
For each directory that is listed, preface the files with a line
`total BLOCKS', where BLOCKS is the total disk allocation for all
files in that directory. The block size currently defaults to 1024
bytes, but this can be overridden (*note Block size::). The
BLOCKS computed counts each hard link separately; this is arguably
a deficiency.
O total vai desde 12a 20quando você usa ls -laem vez de ls -lporque você está contando dois diretórios adicionais: .e ... Você está usando quatro blocos de disco para cada diretório (vazio), portanto, o total varia de 3 × 4 a 5 × 4. (Com toda a probabilidade, você está usando um bloco de disco de 4096 bytes para cada diretório; conforme a infopágina indica, o O utilitário não verifica o formato do disco, mas assume um tamanho de bloco, a 1024menos que seja instruído de outra forma.)
Se você deseja simplesmente obter o número de arquivos, tente algo como
ls | wc -lfalhará se houver arquivos com uma nova linha no nome do arquivo. Isso é mais resiliente:find . -mindepth 1 -maxdepth 1 -printf . | wc -c
Flimm
20
"se os nomes de arquivos têm uma nova linha neles" ... estremecimento
Petah
8
Como man lsserá dito, você pode evitar caracteres de controle com -b(escapa-os) ou -q(omite-os). Portanto, para contar, ls -1q | wc -lé seguro e preciso para mostrar arquivos não ocultos. ls -1qA | wc -lcontar arquivos ocultos (mas não .e ..). Estou usando em -1vez de, -lporque isso deve ser mais rápido.
Oli
18
user4556274 já respondeu o porquê . Minha resposta serve apenas para fornecer informações adicionais sobre como contar corretamente os arquivos.
Na comunidade Unix, o consenso geral é que analisar a saída de lsé uma péssima idéia , já que os nomes de arquivos podem conter caracteres de controle ou caracteres ocultos. Por exemplo, devido a um caractere de nova linha em um nome de arquivo, ls | wc -linformamos que há 5 linhas na saída de ls(que possui), mas, na realidade, existem apenas 4 arquivos no diretório.
$> touch FILE$'\n'NAME
$> ls
file1.txt file2.txt file3.txt FILE?NAME
$> ls | wc -l
5
Método # 1: encontrar utilitário
O findcomando, normalmente usado para solucionar nomes de arquivos de análise, pode nos ajudar aqui imprimindo o número do inode . Seja um diretório ou um arquivo, ele possui apenas um número de inode exclusivo. Assim, usando -printf "%i\n"e excluindo .via -not -name ".", podemos ter uma contagem precisa dos arquivos. (Observe o uso de -maxdepth 1para impedir a descida recursiva em subdiretórios)
Maneira simples, rápida e principalmente portátil:
$ set -- *
$ echo $#
228
setO comando é usado para definir parâmetros posicionais do shell (as $<INTEGER>variáveis, como em echo $1). Isso geralmente é usado para solucionar as /bin/shlimitações de matrizes ausentes. Uma versão que realiza verificações extras pode ser encontrada na resposta de Gille no Unix e Linux.
Em shells que suportam matrizes, como bash, podemos usar
Truque semelhante ao findmétodo usado wce globstar pode ser usado statpara contar números de inodes por linha:
$> LC_ALL=C stat ./* --printf "%i\n" | wc -l
4
Uma abordagem alternativa é usar um curinga no forloop. (Observe, esse teste usa um diretório diferente para testar se essa abordagem é dividida em subdiretórios, o que não ocorre - 16 é o número verificado de itens no meu ~/bin)
$> count=0; for item in ~/bin/* ; do count=$(($count+1)) ; echo $count ; done | tail -n 1
16
Método # 3: outros idiomas / intérpretes
O Python também pode lidar com nomes de arquivos problemáticos, imprimindo o tamanho de uma lista, de acordo com minha os.listdir()função (que não é recursiva, e listará apenas os itens no diretório como argumento).
$> python -c "import os ; print os.listdir('.')"
['file2.txt', 'file1.txt', 'FILE\nNAME', 'file3.txt']
$> python -c "import os ; print(len(os.listdir('.')))"
4
No bash, outra opção seria usar uma matriz, por exemplo items=( dir/* ); echo ${#items[@]}(adicionando shopt -s dotglobpara incluir arquivos ocultos).
steeldriver
1
A impressão de números de inode facilita a filtragem de links físicos, se desejado, com find | sort -u | wc -l.
Peter Cordes
@steeldriver: Acho improvável que o método bash-array seja mais rápido. Se você quiser que seja recursivo, precisará usar items=( dir/** )(with shopt -s globstar), mas o bash não tira proveito de metadados extras do readdir, portanto, ele classifica cada entrada de diretório para ver se é um diretório em si. Muitos sistemas de arquivos armazenam o tipo de arquivo na entrada do diretório, para que o readdir possa retorná-lo sem acessar os inodes. (por exemplo, o XFS não padrão mais recente possui isso, e acho que o ext4 o possui há mais tempo.) Se você straceencontrar, verá muito menos statchamadas do sistema do que o bash.
Peter Cordes
2
Por que não usar apenas print(len(os.listdir('.')))? Menos caracteres para digitar e também evita o acesso a atributos com sublinhado duplo.
ls | wc -l
falhará se houver arquivos com uma nova linha no nome do arquivo. Isso é mais resiliente:find . -mindepth 1 -maxdepth 1 -printf . | wc -c
man ls
será dito, você pode evitar caracteres de controle com-b
(escapa-os) ou-q
(omite-os). Portanto, para contar,ls -1q | wc -l
é seguro e preciso para mostrar arquivos não ocultos.ls -1qA | wc -l
contar arquivos ocultos (mas não.
e..
). Estou usando em-1
vez de,-l
porque isso deve ser mais rápido.user4556274 já respondeu o porquê . Minha resposta serve apenas para fornecer informações adicionais sobre como contar corretamente os arquivos.
Na comunidade Unix, o consenso geral é que analisar a saída de
ls
é uma péssima idéia , já que os nomes de arquivos podem conter caracteres de controle ou caracteres ocultos. Por exemplo, devido a um caractere de nova linha em um nome de arquivo,ls | wc -l
informamos que há 5 linhas na saída dels
(que possui), mas, na realidade, existem apenas 4 arquivos no diretório.Método # 1: encontrar utilitário
O
find
comando, normalmente usado para solucionar nomes de arquivos de análise, pode nos ajudar aqui imprimindo o número do inode . Seja um diretório ou um arquivo, ele possui apenas um número de inode exclusivo. Assim, usando-printf "%i\n"
e excluindo.
via-not -name "."
, podemos ter uma contagem precisa dos arquivos. (Observe o uso de-maxdepth 1
para impedir a descida recursiva em subdiretórios)Método # 2: globstar
Maneira simples, rápida e principalmente portátil:
set
O comando é usado para definir parâmetros posicionais do shell (as$<INTEGER>
variáveis, como emecho $1
). Isso geralmente é usado para solucionar as/bin/sh
limitações de matrizes ausentes. Uma versão que realiza verificações extras pode ser encontrada na resposta de Gille no Unix e Linux.Em shells que suportam matrizes, como
bash
, podemos usarcomo proposto por steeldriver nos comentários .
Truque semelhante ao
find
método usadowc
e globstar pode ser usadostat
para contar números de inodes por linha:Uma abordagem alternativa é usar um curinga no
for
loop. (Observe, esse teste usa um diretório diferente para testar se essa abordagem é dividida em subdiretórios, o que não ocorre - 16 é o número verificado de itens no meu~/bin
)Método # 3: outros idiomas / intérpretes
O Python também pode lidar com nomes de arquivos problemáticos, imprimindo o tamanho de uma lista, de acordo com minha
os.listdir()
função (que não é recursiva, e listará apenas os itens no diretório como argumento).Veja também
fonte
items=( dir/* ); echo ${#items[@]}
(adicionandoshopt -s dotglob
para incluir arquivos ocultos).find | sort -u | wc -l
.items=( dir/** )
(withshopt -s globstar
), mas o bash não tira proveito de metadados extras do readdir, portanto, ele classifica cada entrada de diretório para ver se é um diretório em si. Muitos sistemas de arquivos armazenam o tipo de arquivo na entrada do diretório, para que o readdir possa retorná-lo sem acessar os inodes. (por exemplo, o XFS não padrão mais recente possui isso, e acho que o ext4 o possui há mais tempo.) Se vocêstrace
encontrar, verá muito menosstat
chamadas do sistema do que o bash.print(len(os.listdir('.')))
? Menos caracteres para digitar e também evita o acesso a atributos com sublinhado duplo.