Preciso de um script que conte os arquivos em um diretório (e sub). Peguei o script seguido e mudei de acordo com minha necessidade.
Funciona como deveria, exceto para pastas com caracteres de espaço. Tenho certeza de que estou perdendo aspas em algum lugar, mas ainda não consigo descobrir.
Informações adicionais
- Linux 2.6.22.19-0.4-default (este servidor não está mais em um ambiente produtivo).
- GNU encontra versão 4.2.31
- Não consigo renomear os diretórios.
Exemplo de estrutura de diretório
.
..
01_infos
02_sent
03_inbox
04_public and private
197.
145.
329.
13.
Roteiro
#!/bin/bash
# Write a script that will count the number of files in each of your subdirectories.
# -------------------------------------------------------------------------
# Copyright (c) 2001 nixCraft project <http://cyberciti.biz/fb/>
# This script is licensed under GNU GPL version 2.0 or above
# -------------------------------------------------------------------------
# This script is part of nixCraft shell script collection (NSSC)
# Visit http://bash.cyberciti.biz/ for more information.
# -------------------------------------------------------------------------
START=$HOME
# change your directory to command line if passed
# otherwise use home directory
[ $# -eq 1 ] && START=$1 || :
if [ ! -d $START ]
then
echo "$START not a directory!"
exit 1
fi
# use find command to get all subdirs name in DIRS variable
DIRS=$(find "$START" -type d)
# loop thought each dir to get the number of files in each of subdir
for d in $DIRS
do
echo "$d directory has $(find "$d" -maxdepth 1 -regex '.*\.' -type f | wc -l) files" || :
done
saída
./01_infos directory has 1 files
./02_sent directory has 9 files
./03_inbox has 4 files
find: ./04_public: No such file or directory
Responder1
Estão faltando algumas aspas duplas (sempre coloque aspas duplas em substituições de variáveis $foo
e substituições de comandos$(foo)
, a menos que você saiba por que pode deixá-los desligados com segurança e precisa deixá-los desligados). Mas esse não é todo o problema.
if [ ! -d $START ]
deveria estar if [ ! -d "$START" ]
.
DIRS=$(find "$START" -type d)
Neste ponto, DIRS
contém o nome do diretório inicial e seus subdiretórios recursivamente, com novas linhas entre eles. Portanto, se você tiver algum nome de diretório que contenha uma nova linha, você perdeu: é impossível saber quais novas linhas vieram de um nome de diretório e quais eram separadores. Se você souber que não há novas linhas nos nomes dos arquivos, poderá analisar a saída de find
, mas como saberia?
A propósito, não há problema em não colocar aspas duplas por $(…)
aqui porque se trata de atribuições de variáveis, e as substituições nas atribuições são implicitamente protegidas. No entanto, observe que não é protegido de forma semelhante. É melhor usar aspas, a menos que você seja fluente em scripts de shell, assim como todas as pessoas que manterão seu script.export DIRS=$(…)
for d in $DIRS
É aqui que você perde: você quer dividir $DIRS
em palavras, então não pode colocar aspas duplas, mas precisa de aspas duplas porque $DIRS
todos os elementos estão concatenados e os nomes dos arquivos dentro dos espaços seriam separadores se você os deixasse sem aspas.
Normalmente, ao usar find
, você deve fazer com que ele invoque o comando de processamento, com a -exec
opção. A menos que você tenha controles rígidos sobre os nomes dos arquivos, não analise a saída de find
: é ambígua.
find "$START" -type d -exec sh -c '
echo "$0 directory has $(find "$0" -maxdepth 1 -regex ".*\\." -type f -printf \\n | wc -l) files whose name ends with ."
' {} \;
Observe novamente no find
comando incorporado que se você analisar a saída de find
, sua contagem será desativada se algum nome de arquivo contiver uma nova linha.
Responder2
Que tal apenas isso?
find . -type d -exec sh -c '/bin/echo -n "{}"; find "{}" -maxdepth 1 -regex ".*\." -type f | wc -l; ' \;
A saída não é tão açucarada, mas não requer script e funciona para diretórios com espaços, bem como outros caracteres não alfanuméricos.
Responder3
Você cometeu um erro clássico de citação. Corrija o loop for para ficar assim:
for d in "$DIRS"
Alternativamente, você pode alimentar find
a saída diretamente, por exemplo:
find "$START" -type d | while read d
do # and so on...
Além disso, o || :
bit é completamente redundante, pois echo
sempre tem valor de retorno 0.