Como usar o wc e o piping para descobrir quantos arquivos e diretórios estão em um determinado diretório?

8

Como posso usar o contador de palavras ( wc ) e a tubulação para contar quantos arquivos ou diretórios estão no diretório /usr/bin ?

    
por cash 16.11.2013 / 15:21

4 respostas

11

Uma abordagem seria usar ls para nos fornecer uma lista dos arquivos, mas queremos que essa lista mostre apenas 1 arquivo ou diretório por linha. A opção -1 fará isso por nós.

$ ls -1
dir1
dir2
dir3
fileA
fileB
fileC

Exemplo

Crie os dados de amostra acima em um diretório vazio.

$ mkdir dir{1..3}
$ touch file{A..C}

Verifique:

$ ls
dir1  dir2  dir3  fileA  fileB  fileC

Agora, para contar, você pode usar wc -l para contar o número de linhas, que correspondem a um arquivo ou diretório na ls -1 output.

$ ls -1 | wc -l
6

(note que não inclui os arquivos ocultos)

Contando arquivos ou diretórios, apenas não juntos

Para contar arquivos ou diretórios, você precisa alterar um pouco a sua tática. Nesse caso, usaria ls -l , já que mostra o que é um diretório e o que é um arquivo.

Exemplo

$ ls -l
total 12
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir1
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir2
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir3
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileA
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileB
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileC

Em seguida, podemos usar grep para filtrar diretórios ou não diretórios da seguinte forma:

# directories
$ ls -l | grep "^d"
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir1
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir2
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir3

# regular files
$ ls -l | grep "^-"
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileA
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileB
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileC

Agora é só usar wc -l para contar o acima:

# directories
$ ls -l | grep "^d" | wc -l
3

# regular files
$ ls -l | grep "^-" | wc -l
3

No entanto, você pode evitar wc completamente e usar a opção grep de -c :

$ ls -l | grep -c '^d'

(mais uma vez, arquivos ocultos não são incluídos. Note que diretórios e regulares são dois tipos de arquivos. Existem muitos mais como pipes nomeados, links simbólicos, dispositivos, sockets ...).

Recursão

Se você precisar encontrar os arquivos e diretórios de forma recursiva em /usr/bin , provavelmente desejará alterar completamente as táticas e usar outra ferramenta chamada find .

Exemplo

$ find /usr/bin | wc -l
4632

(embora acima de /usr/bin esteja incluído na contagem)

As mesmas técnicas que usei acima podem ser empregadas use ls para fazer algo semelhante, mas ls geralmente não é uma boa ferramenta para analisar a saída. find , por outro lado, foi criado para isso e oferece opções para localizar arquivos ou diretórios.

# find files
$ find /usr/bin -type f

# find directories
$ find /usr/bin -type d

(observe que, desta vez, find está incluindo arquivos ocultos (exceto . e .. )).

novas linhas?

Eu nunca descobri por que um caractere de nova linha é um caractere legal a ser usado na criação de nomes de arquivos ou de diretórios. Portanto, os métodos discutidos acima usando wc e ls não seriam compatíveis com eles, portanto, use-os com isso em mente.

Exemplo

Crie um diretório & nome do arquivo com novas linhas.

$ mkdir $'dir4\n5'
$ touch $'fileD\nE'

ls mostra-os corretamente:

$ ls -1
dir1
dir2
dir3
dir4?5
fileA
fileB
fileC
fileD?E

Mas wc conta os diretórios e arquivos que contêm novas linhas como 2 itens, não um.

$ ls -1 | wc -l
10

Um método para contornar isso, se usar a implementação GNU de find é usar a capacidade de find de imprimir outra coisa no lugar de cada arquivo que encontrar e, em seguida, contá-los.

Exemplo

$ find . -printf . | wc -c
9

Aqui encontramos tudo no diretório atual (exceto .. ), e imprimimos um ponto ( . ) para cada um e depois contamos os pontos usando a capacidade de wc de contar bytes em vez de linhas wc -c .

Referências

por 16.11.2013 / 15:51
5

Se você deseja obter uma divisão do número de cada tipo de arquivo recursivamente em algum diretório, com GNU find , você poderia fazer:

find /some/dir/. ! -name . -printf '%y\n' | sort | uniq -c | sed '
  s/f/regular files/;t
  s/d/directories/;t
  s/l/symbolic links/;t
  s/s/Unix domain sockets/;t
  s/b/block devices/;t
  s/c/character devices/;t
  s/p/FIFOs/;t
  s/D/Doors/;t
  s/n/network special files/;t
  s/.$/others (&)/'

Em /usr/bin no meu sistema, isso dá:

   3727 regular files
    710 symbolic links

Em /dev :

     83 block devices
    203 character devices
     31 directories
    426 symbolic links
      1 FIFOs
      1 Unix domain sockets

Para links simbólicos, se você preferir contabilizá-los como o tipo de arquivo para o qual eles apontam, em vez de symbolic links , você pode alterá-lo para:

find /some/dir/. ! -name . -printf '%Y\n' | sort | uniq -c | sed '
  s/f/regular files/;t
  s/d/directories/;t
  s/N/broken symbolic links/;t
  s/s/Unix domain sockets/;t
  s/b/block devices/;t
  s/c/character devices/;t
  s/p/FIFOs/;t
  s/D/Doors/;t
  s/n/network special files/;t
  s/.$/others (&)/'

O que agora dá para meu /usr/bin :

      1 directories
   4434 regular files
      2 broken symbolic links

(um link simbólico quebrado é um link simbólico para um arquivo para o qual find não pode determinar o tipo porque o arquivo não existe ou está em um diretório ao qual você não tem acesso ou há um loop na resolução do caminho do arquivo. No meu caso, aqueles 2 onde links simbólicos para os arquivos que agora se foram).

Nenhum desses conta . e .. . Se você queria que eles fossem incluídos (por que você faria isso?), Não há outra maneira com find do que assumir que eles estão lá para cada diretório e contá-los sistematicamente:

find /some/dir/. -printf '%y\n' \( -name . -printf 'd\n' -o \
  -type d -printf 'd\nd\n' \)  | sort | uniq -c | sed '
  s/f/regular files/;t
  s/d/directories/;t
  s/l/symbolic links/;t
  s/s/Unix domain sockets/;t
  s/b/block devices/;t
  s/c/character devices/;t
  s/p/FIFOs/;t
  s/D/Doors/;t
  s/n/network special files/;t
  s/.$/others (&)/'

O que então dá no meu /usr/bin :

      2 directories
   3727 regular files
    710 symbolic links

Se você não tem acesso ao GNU find , você pode reescrever o primeiro como:

find /some/dir/. ! -name . \( \
  -type f -exec printf '%.0sregular files\n' {} + -o \
  -type d -exec printf '%.0sdirectories\n' {} + -o \
  -type l -exec printf '%.0ssymbolic links\n' {} + -o \
  -type s -exec printf '%.0sUnix domain sockets\n' {} + -o \
  -type b -exec printf '%.0sblock devices\n' {} + -o \
  -type c -exec printf '%.0scharacter devices\n' {} + -o \
  -type p -exec printf '%.0sFIFOs\n' {} + -o \
  -exec printf '%.0sothers\n' {} + \) | sort | uniq -c

Agora, estritamente falando, não estamos contando arquivos , mas entradas de diretório . Um diretório como /usr/bin normalmente possui várias entradas que apontam para o mesmo arquivo. Por exemplo, aqui eu tenho:

$ ls -lid /usr/bin/{nvi,nview,nex}
672252 -rwxr-xr-x 3 root root 434616 May 25 07:40 /usr/bin/nex
672252 -rwxr-xr-x 3 root root 434616 May 25 07:40 /usr/bin/nvi
672252 -rwxr-xr-x 3 root root 434616 May 25 07:40 /usr/bin/nview

São 3 entradas de diretório (também chamadas de hard links) para o mesmo arquivo (o inode 672252). Para contar arquivos em vez de entradas de diretório e com GNU find e GNU uniq (ignorando . e .. arquivos que, de qualquer forma, são hard links para outros diretórios):

find /some/dir/. ! -name . -printf '%y\t%D:%i\n' |
  sort -u |
  cut -f1 |
  uniq -c |
  sed '
    s/f/regular files/;t
    s/d/directories/;t
    s/l/symbolic links/;t
    s/s/Unix domain sockets/;t
    s/b/block devices/;t
    s/c/character devices/;t
    s/p/FIFOs/;t
    s/d/Doors/;t
    s/n/network special files/;t
    s/.$/others (&)/'

No meu /usr/bin , isso dá:

   3711 regular files
    710 symbolic links
    
por 16.11.2013 / 22:05
0

Você não disse se deseja todo o arquivo em / usr / bin de forma recursiva ou apenas abaixo do primeiro nível. Além disso, como você vai conseguir as palavras que você está contando? A maneira usual de descobrir é correr encontrar em wc. Como isso: encontrar / usr / bin | wc -l Encontrar listará tudo lá, diretórios e amp; arquivos. Wc -l contará todas as linhas na saída de localização. Isto é uma tarefa de classe? Tudo bem se for, mas eu estava me perguntando por que você precisava dessa informação para que eu pudesse adaptar a resposta com mais cuidado. Por favor, deixe-me saber se você precisar de mais. Costa

    
por 16.11.2013 / 15:55
0

No bash, sem ferramentas externas.

cd dir/ || exit; shopt -s nullglob; shopt -s dotglob; count=(*); echo "${#count}"

No bash, sem ferramentas externas e recursão.

shopt -s globstar; shopt -s dotglob 
for dir in **/*/; do 
  unset d f
  for files in "$dir"*; do 
    [[ -f $files ]] && ((++f))
    [[ -d $files ]] && ((++d))
  done; 
  printf '%s\n' "$dir -  files: ${f:-0} - directories: ${d:-0}"
done
    
por 16.11.2013 / 16:59