Conte arquivos em uma árvore de diretórios [duplicado]

0

Para a verificação de consistência de um programa de backup, quero definir uma função que conte todos os arquivos em um diretório, incluindo todos os arquivos em subdiretórios, subsubdirs e assim por diante.

A solução que estou tentando até agora é a seguinte:

countfiles() {
  local cdir=$1
  local files=$(ls -la $cdir | grep -cv '^[dl]')

  local dirstring=$(ls -la $cdir | grep '^d' | egrep -o ' \.?[^[:space:].][^[:space:]]+$')
  local directories=(${dirstring//"\n"/})

  echo ${directories[@]}


  for dir in ${directories[@]}; do
    echo -n "$dir "
    echo -n 'filecount >> '
    local dirfiles=$(countfiles "$cdir/$dir")
    echo -n $dirfiles
    echo ' <<'
    #files=$(($files+$dirfiles))
  done

  echo $files

}

O que me dá a seguinte saída:

.config .i3 .scripts
.config filecount >> gtk-3.0 termite gtk-3.0 filecount >> 2 << termite filecount >> 2 << 1 <<
.i3 filecount >> 5 <<
.scripts filecount >> 2 <<
5

Enquanto a atualização do meu $files counter é comentada em atm e eu posso precisar para unlocalize-lo, agora eu defino todas as variáveis como locais para evitar qualquer interferência.

A árvore de diretórios é a seguinte:

/.scripts/backup_dotfiles.sh
/.config/termite/config
/.config/gtk-3.0/settings.ini
/.i3/config
/.i3/i3blocks.conf
/.i3/lockicon.png
/.i3/lockscreen.sh
/.gtkrc-2.0
/.bashrc
/.zshrc
/.i3
/.Xresources

Minhas perguntas:

  • Por que ele sempre conta os arquivos +1, exceto o diretório principal?
  • Por que conta tudo no diretório '.config', pois não há arquivos lá?
  • Como posso corrigir isso?
por tillyboy 08.07.2017 / 13:31

3 respostas

6

Você provavelmente deseja usar apenas find . Supondo que você não tenha arquivos com novas linhas em seus nomes, apenas algo assim faria:

find "$dir" -type f | wc -l

-type f corresponde a arquivos regulares, mas não a diretórios, pipes, soquetes ou o que for.

A saída usual de find separa os nomes de arquivos por novas linhas, portanto, se algum dos nomes contiver novas linhas, a saída será ambígua. Com o GNU find, algo assim funcionaria:

find "$dir" -type f -printf . | wc -c

Isso tem find imprime apenas um ponto para cada arquivo e conta os pontos.

Outras versões do find não têm -printf , mas podemos usar o truque de passar o caminho de entrada com barras duplas. Eles são tratados como uma única barra, mas não aparecerão naturalmente na saída, pois os nomes de arquivos não podem conter barras. Em seguida, conte as barras duplas na saída:

find "$dir//" -type -f | grep -c //

Se quisermos fazer isso com puramente um script de shell, podemos ter o shell listar os nomes de arquivo, não é necessário usar ls , por exemplo no Bash:

#!/bin/bash
files=0
shopt -s dotglob
countfiles() {
        local f;
        for f in * ; do 
                if [ -f "$f" ] ; then          # count regular files
                        files=$((files + 1))
                elif [ -d "$f" ] ; then        # recurse into directories
                        cd "$f"
                        countfiles
                        cd ..
                fi
        done
}
cd "$1"
countfiles
echo $files
    
por 08.07.2017 / 14:09
1

Você pode obter o número de arquivos em um diretório e sub-diretórios usando:

 find path_to_directory -type f | wc -l
    
por 08.07.2017 / 13:49
0

Why does it always count the files +1 except for the master directory?

Causa ls -la também adiciona a string total 20 à saída. Eu posso ver que para o diretório "master" também mostra o valor +1.

Why does it count anything in the '.config' directory, as there are no files in there?

O mesmo motivo. total .. string produzida por ls .

How can I fix this?

Não use seu script :) Quero dizer, é supercomplicada. Temos um bom find aqui. Todo o seu script se transformará em algo assim (se você precisar de arquivos por diretório):

find $yourdir -type d | while read dir ; do 
    echo "$dir == $(find $dir -maxdepth 1 -type f | wc -l) files" ; 
done

ou apenas (se você precisar de valor de soma):

find $yourdir -type f | wc -l
    
por 08.07.2017 / 13:51