Como você lista o número de linhas de cada arquivo em um diretório em formato legível por humanos.

41

Eu tenho uma lista de diretórios e subdiretórios que contêm arquivos csv grandes. Existem cerca de 500 milhões de linhas nesses arquivos, cada um é um recorde. Eu gostaria de saber

  1. Quantas linhas existem em cada arquivo.
  2. Quantas linhas estão no diretório
  3. Quantas linhas no total

Mais importante, eu preciso disso em "formato legível por humanos", por exemplo. 12.345.678 em vez de 12345678

Seria bom aprender como fazer isso de três maneiras. Ferramentas simples de baunilha, awk etc. e perl (ou python).

Hexatonic
fonte

Respostas:

57

Quantas linhas existem em cada arquivo.

Use wc, originalmente para contagem de palavras, acredito, mas ele pode fazer linhas, palavras, caracteres, bytes e o maior comprimento de linha. A -lopção diz para contar linhas.

wc -l <filename>

Isso produzirá o número de linhas em:

$ wc -l /dir/file.txt
32724 /dir/file.txt

Você também pode canalizar dados para wc:

$ cat /dir/file.txt | wc -l
32724
$ curl google.com --silent | wc -l
63

Quantas linhas estão no diretório

Experimentar:

find . -name '*.pl' | xargs wc -l

outro one-liner:

( find ./ -name '*.pl' -print0 | xargs -0 cat ) | wc -l

BTW, o wccomando conta novos códigos de linhas, não linhas. Quando a última linha do arquivo não termina com o novo código de linha, isso não conta.

Você pode usar grep -c ^, exemplo completo:

#this example prints line count for all found files
total=0
find /path -type f -name "*.php" | while read FILE; do
     #you see use grep instead wc ! for properly counting
     count=$(grep -c ^ < "$FILE")
     echo "$FILE has $count lines"
     let total=total+count #in bash, you can convert this for another shell
done
echo TOTAL LINES COUNTED:  $total

Quantas linhas no total

Não tenho certeza de que entendi que você solicitou corretamente. por exemplo, isso produzirá resultados no seguinte formato, mostrando o número de linhas para cada arquivo:

# wc -l `find /path/to/directory/ -type f`
 103 /dir/a.php
 378 /dir/b/c.xml
 132 /dir/d/e.xml
 613 total

Como alternativa, a saída apenas do número total de caracteres de nova linha sem o arquivo por arquivo conta para o seguinte comando pode ser útil:

# find /path/to/directory/ -type f -exec wc -l {} \; | awk '{total += $1} END{print total}'
 613

Mais importante, eu preciso disso em "formato legível por humanos", por exemplo. 12.345.678 em vez de 12345678

O Bash possui uma função printf integrada em:

printf "%0.2f\n" $T

Como sempre, existem muitos métodos diferentes que podem ser usados ​​para obter os mesmos resultados mencionados aqui.

malyy
fonte
A propósito, como uso printf em seus exemplos? Tentei canalizá-lo de wc -l, mas não funcionou.
Hexatonic
tente> encontrar. -name '* .pl' | xargs wc -l | awk '{printf ("% 0.2f", $ 1)} {print $ 2}' altere a saída de 'printf' para suas necessidades
malyy
Isso não adiciona vírgulas ao número para torná-lo mais legível para humanos. Apenas adiciona zeros ao final.
Hexatonic 8/16
eco 1000000000000 | xargs printf "% 'd \ n" 1.000.000.000.000
Hexatonic
1
O @Hexatonic printfnão lê seus argumentos stdin, mas na linha de comando (compare tubulação com echovs tubulação cat; catlê de stdin, echonão). Em vez disso, use printf "$(find ... | xargs ...)"para fornecer a saída como argumentos para printf.
usar o seguinte
13

Em muitos casos, combinar o wccomando e o curinga *pode ser suficiente.
Se todos os seus arquivos estiverem em um único diretório, você poderá ligar para:

wc -l src/*

Você também pode listar vários arquivos e diretórios:

wc -l file.txt readme src/* include/*

Este comando mostra uma lista dos arquivos e seu número de linhas.
A última linha será a soma das linhas de todos os arquivos.


Para contar todos os arquivos em um diretório recursivamente:

Primeiro, ative a globstar adicionando shopt -s globstarao seu .bash_profile. O suporte ao globstar requer o Bash ≥ 4.x, que pode ser instalado com o brew install bashnecessário. Você pode verificar sua versão com bash --version.

Então corra:

wc -l **/*

Observe que esta saída estará incorreta se o globstar não estiver ativado.

Thomio
fonte
E para contar arquivos no diretório atual recursivamente:wc -l **/*
Taylor Edmiston
@TaylorEdmiston Para mim (no Mac), apenas os arquivos são contabilizados exatamente em um diretório. Ele ignora os arquivos no diretório atual e, para qualquer instância que tenha mais de um diretório, avisa que é um diretório: " wc: parent_dir/child_dir: read: Is a directory"
M. Justin
@ Thomio Requer que o globstar esteja ativado. No macOS, acredito que ele esteja desativado imediatamente. Acabei de enviar uma edição para sua resposta que adiciona o comando e como ativar o globstar.
Taylor Edmiston
2

Este comando fornecerá o código da lista de linhas em cada diretório:

find . -name '*.*' -type f | xargs wc -l
Suresh.A
fonte
2

um pouco atrasado para o jogo, mas recebi um monte de erros de argumento com o acima exposto devido ao tamanho do dir. Isso funcionou para mim:

for i in $(find . -type f); do wc -l $i; done >> /home/counts.txt

Ron Paulfan
fonte
0

catcombinaria os arquivos em um e produziria tudo para stdout, você pode fazer wc -lisso para uma contagem total de linhas de arquivos em um diretório:

cat /path/to/directory/* | wc -l
picmate 涅
fonte
0

Vou apenas aumentar a resposta @malyy para o seguinte (grande para um comentário):

Quantas linhas no total

Muitas respostas estão usando a wcopção de arquivo de linha de comando com xargs. O problema disso é que o xargs está limitado a um tamanho dependente da plataforma bastante pequeno.

Além disso, há uma diferença entre BSD (macOS) e GNU (linux / homebrew) wc.

O GNU é ideal porque pode ler a lista de arquivos de um arquivo em vez de argumentos ( --files0).

Se você estiver no mac e tiver um homebrew, faça o seguinte:

find . -name "*.pl" -print0 | gwc -l --files0=-

Observe o gwc em vez de wc .

Adam Gent
fonte