Supondo que seus nomes de arquivo não contenham caracteres de nova linha e seu grep
suporta a opção -o:
find [[:upper:]] -type f | grep -Eo '^./[0-9]{3}' | sort | uniq -c
Eu tenho muitos e muitos arquivos em uma série de diretórios, e gostaria de uma lista bem formatada de quantos arquivos estão em cada diretório.
Os diretórios são ordenados assim: Diretórios pai denominados A, B, ... H, I. Sob cada um desses, há de 1 a 7 diretórios denominados 001, 002, ... 007. Nesses diretórios, Eu gostaria de contar os arquivos.
O que eu espero é algo assim:
... C/003 122 C/004 45 C/005 462 D/001 215 E/001 98 E/002 323 ...
Estou pensando em uma guia entre nome do diretório e contagem. Não importa se a contagem é justificada à esquerda ou à direita.
O que eu fiz sozinho é basicamente isso:
( for i in */* do echo ">>> $i" ls "$i" | wc done ) > file_count
O resultado é algo assim:
... >>> F/002 30 30 234 >>> F/003 120 120 1322 >>> G/001 78 78 620 ...
Obviamente, nada mal ... e se eu substituí wc
por wc -l
e removi o "> > >" seria ainda melhor - exceto que cada "registro" seria mais de duas linhas em vez de uma.
Então, o que eu preciso é de alguma awk
ou sed
(ou qualquer que seja - existe uma ferramenta mais simples para unir duas linhas do que essas duas?) mágica para unir as duas e duas linhas em uma.
No entanto, se houver uma abordagem mais direta (shell-script, perl, python, algum realmente escuro sed & awk magic) que poderia fazer uma lista em "uma vez", isso seja ainda melhor ...
Supondo que seus nomes de arquivo não contenham caracteres de nova linha e seu grep
suporta a opção -o:
find [[:upper:]] -type f | grep -Eo '^./[0-9]{3}' | sort | uniq -c
Você pode criar uma matriz de arquivos para cada diretório separadamente e, em seguida, apenas contar o número de elementos. Em bash
, isso seria algo como
for dir in */*/; do a=( "$dir"/* ); printf "%s\t%s\n" "$dir:" "${#a[@]}"; done
Se A/001
etc. contiver diretórios também que conteúdo você gostaria de incluir, adicione **
glob:
shopt -s globstar
for dir in */*/; do a=( "$dir"/**/* ); printf "%s\t%s\n" "$dir:" "${#a[@]}"; done
A maneira mais simples de obter o que você deseja é usar a opção -n
para echo
ao imprimir o nome do diretório. Isso evita imprimir uma nova linha no final do que você está fazendo eco, então a próxima saída permanece na mesma linha. Outros idiomas podem ser uma opção melhor se você quiser coletar as informações que está procurando e, em seguida, executar várias transformações antes de fornecer a saída.
Isso fará o que você pediu:
for d in */*
do
n=$(find "$d" -maxdepth 1 -type f -printf "ok\n" | wc -l)
printf "%s\t%d\n" "$d" $n
done
As principais diferenças para o seu código são que usei find
em vez de ls
para que arquivos com nomes estranhos não quebrem a contagem (pense em \n
em um nome de arquivo), e que eu tenha usou printf
para formatar a saída.
Talvez algo como:
find $PWD/ -type f -printf "%h\n 7 /foo
17 /foo/bar
9 /foo/baz
" | uniq -zc
Renda algo como:
find $PWD/ -type f -printf "%h\n 7 /foo
17 /foo/bar
9 /foo/baz
" | uniq -zc
Adicione um | sort -z
antes de | uniq
para classificá-lo.