Qual é a melhor maneira de contar o número de arquivos em um diretório?


11

Se a análise da saída de lsé perigosa, pois pode quebrar alguns caracteres descolados (espaços \n, ...), qual é a melhor maneira de saber o número de arquivos em um diretório?

Geralmente confio findpara evitar essa análise, mas, da mesma forma, find mydir | wc -lserá interrompida pelos mesmos motivos.

Estou trabalhando no Solaris agora, mas estou procurando uma resposta o mais portátil possível em diferentes unidades e diferentes tipos de conchas.


3
Não tenho certeza se é uma duplicata, estou perdendo alguma coisa?
R17 #

1
Isso pode ser uma duplicata, mas não da pergunta indicada. findvai te número de arquivos de forma recursiva (use -maxdepth 1se você não quer isso. find mydir -maxdepth 1 -type f -printf \\n | wc -ldeve lidar com os caracteres especiais no nome do arquivo, como eles nunca são impressos em primeiro lugar.
Anthon

Respostas:


15

Que tal esse truque?

find . -maxdepth 1 -exec echo \; | wc -l

Tão portátil quanto finde wc.


5
Isso não funciona (ele exibe n+1arquivos no meu sistema Debian). Também não filtra arquivos regulares.
Chris Baixo

4
Eu apenas dei um exemplo genérico. Ele faz o trabalho, mas como ele funciona depende de como você adaptar o findcomando para suas necessidades específicas. Sim, este inclui todos os diretórios, incluindo .(o que pode ser o motivo pelo qual você vê o resultado n+1).
rozcietrzewiacz

Eu gosto desse truque, muito inteligente; mas estou surpreso que não haja uma maneira simples e direta de fazer isso!
rahmu

3
@ChrisDown, o OP não especifica a filtragem de arquivos regulares, solicita o número de arquivos em um diretório. Para se livrar do problema n + 1, use find . -maxdepth 1 ! -name . -exec echo \; | wc -l; algumas versões mais antigas finddo não possuem -not.
Arcege

3
Observe que isso -maxdepthnão é padrão (uma extensão GNU agora também é suportada por algumas outras implementações).
Stéphane Chazelas

11

Com bash, sem utilitários externos, nem loops:

shopt -s dotglob
files=(*)
echo ${#files[@]}

Em ksh, substitua shopt -s dotglobpor FIGNORE=.?(.). No zsh, substitua-o por setopt glob_dotsou remova a shoptchamada e use files=(*(D)). (Ou simplesmente largue a linha se não quiser incluir arquivos de ponto.) De maneira portável, se você não se importa com arquivos de ponto:

set -- *
echo $#

Se você deseja incluir arquivos de ponto:

set -- *
if [ -e "$1" ]; then c=$#; else c=0; fi
set .[!.]*
if [ -e "$1" ]; then c=$((c+$#)); fi
set ..?*
if [ -e "$1" ]; then c=$((c+$#)); fi
echo $c

2
O primeiro exemplo imprime 1para um diretório vazio quando nullglobnão está ativado. No zsh, a=(*(DN));echo ${#a}com o qualificador N( nullglob) não resulta em erro para um diretório vazio.
Nisetama

8
find . ! -name . -prune -print | grep -c /

Deve ser bastante portátil para os sistemas pós-anos 80.

Isso conta todas as entradas do diretório, exceto .e ..no diretório atual.

Para contar arquivos em subdiretórios também:

find .//. ! -name . | grep -c //

(esse deve ser portátil mesmo para o Unix V6 (1975), já que não é necessário -prune)


Uma das raras respostas portáteis desta página, se não a única.
xhienne

Votou esta resposta ontem ontem, pois achei que também funciona bem para diretórios diferentes do diretório atual ( find dirname ! -name dirname -prune -print). Desde então, tenho me perguntado se existe algum motivo específico para usar em grep -c /vez de wc -l(o que provavelmente é mais comumente usado para contar).
Anthony Geoghegan

1
find dirname ! -name dirnamenão funciona se houver outros diretórios nomeados dirname. É melhor usar find dirname/. ! -name .. wc -lconta o número de linhas, os nomes de arquivos podem ser feitos de várias linhas, pois o caractere de nova linha é tão válido quanto qualquer outro em um nome de arquivo.
Stéphane Chazelas

6

Experimentar:

ls -b1A | wc -l

O -bterá caracteres não imprimíveis, -Airá mostrar todos os arquivos, exceto .e ..e um por linha (o padrão em uma tubulação, mas bom para ser explícito).

Contanto que incluamos linguagens de script de nível superior, aqui está uma linha em Python:

python -c 'import os; print len(os.listdir(os.sep))'

Ou com o 'find' completo:

python -c 'import os; print len([j for i in os.walk(os.sep) for j in i[1]+i[2]])'

1

Yoc pode usar essa construção:

I=0; for i in * ; do ((I++)); done ; echo $I

Mas eu tenho medo, você pode errar como Argument list too long. no caso de ter muitos arquivos no diretório. No entanto, eu testei no diretório com 10 bilhões de arquivos e funcionou bem.


3
Isso não funcionará para arquivos ocultos, a menos que o shell esteja configurado para expandi-los *.
Lekensteyn

gnu find . -maxdepth 1 -type f | wc -l
Nikhil Mulley

4
@ Rush: este comando nunca deve aumentar a "lista de argumentos muito longa". Isso só acontece com o comando externo (portanto, nunca com for.
enzotib

1

Você já considerou o perl, que deve ser relativamente portátil?

Algo como:

use File::Find;

$counter = 0;

sub wanted { 
  -f && ++$counter
}

find(\&wanted, @directories_to_search);
print "$counter\n";

0

Tente isto => Usando ls com -i (por número de nó) & F (acrescenta nome do diretório com '/') opções.

ls -ilF | egrep -v '/' | wc -l

0

Com uma perllinha (reformatada para facilitar a leitura):

perl -e 'opendir($dh, ".");
         while ( readdir($dh) ) {$count++};
         closedir $dh;
         print "$count\n";'

ou

perl -e 'opendir($dh, ".");
         @files = readdir($dh);
         closedir $dh;
         print $#files+1,"\n";'

Você pode usar perlfunções que modificam matrizes como grepou mapcom a segunda versão. Veja perldoc -f readdirum exemplo usando grep.


0

A versão mais simples que eu uso o tempo todo e nunca tive problemas é: ls -b1 | wc -l


Você pode ter problemas se o nome do arquivo contiver um \nou outros caracteres descolados (sim, alguns departamentos permitem isso).
rahmu

1
Eu tentei isso explicitamente antes de postar minha resposta e não tive problemas com ela. Eu usei o gerenciador de arquivos nautilus para renomear um arquivo para conter \ n para tentar isso.
Peter

Você está certo, não funciona assim. Não sei o que fiz quando testei isso primeiro. Tentei novamente e atualizei minha resposta.
Peter

Não, o comando está OK, mas já existe uma solução semelhante e os arquivos ocultos não são contados.
xhienne

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.