Existe um comando bash que conta o número de arquivos que correspondem a um padrão?
Por exemplo, quero obter a contagem de todos os arquivos em um diretório que corresponda a esse padrão: log*
Este simples liner deve funcionar em qualquer shell, não apenas no bash:
ls -1q log* | wc -l
ls -1q fornecerá uma linha por arquivo, mesmo que contenham espaços em branco ou caracteres especiais, como novas linhas.
A saída é canalizada para wc -l, que conta o número de linhas.
-l
, uma vez que isso exigestat(2)
em cada arquivo e, para fins de contagem, não acrescenta nada.ls
, pois cria um processo filho.log*
é expandido pelo shell, nãols
, então um simplesecho
seria.logs
no diretório em questão, o conteúdo desse diretório de logs também será contado. Provavelmente isso não é intencional.Você pode fazer isso com segurança (ou seja, não será incomodado por arquivos com espaços ou
\n
em seus nomes) com o bash:É necessário ativar
nullglob
para que você não obtenha o literal*.log
na$logfiles
matriz se nenhum arquivo corresponder. (Consulte Como "desfazer" um 'set -x'? Para exemplos de como redefini-lo com segurança.)fonte
shopt -u nullglob
deve ser ignorada senullglob
não estiver definida, então você começou.*.log
por apenas*
contará diretórios. Se os arquivos que você deseja enumerar tiverem a convenção de nomenclatura tradicionalname.extension
, use*.*
.Muitas respostas aqui, mas algumas não levam em consideração
-l
)*.log
vez delog*
logs
que correspondelog*
)Aqui está uma solução que lida com todos eles:
Explicação:
-U
fazls
com que não classifique as entradas, o que significa que não precisa carregar toda a lista de diretórios na memória-b
imprime escapes no estilo C para caracteres não gráficos, fazendo com que novas linhas sejam impressas como\n
.-a
imprime todos os arquivos, mesmo arquivos ocultos (não é estritamente necessário quando a globlog*
não implica arquivos ocultos)-d
imprime diretórios sem tentar listar o conteúdo do diretório, o quels
normalmente faria-1
garante que ele esteja em uma coluna (o ls faz isso automaticamente ao gravar em um pipe, por isso não é estritamente necessário)2>/dev/null
redireciona o stderr para que, se houver 0 arquivos de log, ignore a mensagem de erro. (Observe que issoshopt -s nullglob
faria comls
que listasse todo o diretório de trabalho.)wc -l
consome a listagem de diretórios enquanto ela está sendo gerada, portanto a saída dels
nunca fica na memória em nenhum momento.--
Os nomes dos arquivos são separados do comando usando-os--
para não serem entendidos como argumentos parals
(casolog*
seja removido)O shell se expandirá
log*
para a lista completa de arquivos, o que pode esgotar a memória se houver muitos arquivos; portanto, executá-lo no grep é melhor:Este último lida com diretórios extremamente grandes de arquivos sem usar muita memória (embora use um subshell). O
-d
não é mais necessário, porque está listando apenas o conteúdo do diretório atual.fonte
Para uma pesquisa recursiva:
wc -c
contará o número de caracteres na saída defind
, enquanto-printf x
informafind
para imprimir um únicox
para cada resultado.Para uma pesquisa não recursiva, faça o seguinte:
fonte
-name '*.log'
, ele contará todos os arquivos, que é o que eu precisava para o meu caso de uso. Além disso, o sinalizador -maxdepth é extremamente útil, obrigado!find
; basta imprimir algo diferente do nome do arquivo literal.A resposta aceita para esta pergunta está errada, mas eu tenho um representante baixo, portanto não consigo adicionar um comentário.
A resposta correta para esta pergunta é dada por Mat:
O problema com a resposta aceita é que wc -l conta o número de caracteres de nova linha e os conta mesmo se eles imprimirem no terminal como '?' na saída de 'ls -l'. Isso significa que a resposta aceita FALHA quando um nome de arquivo contém um caractere de nova linha. Eu testei o comando sugerido:
e informa erroneamente um valor 2, mesmo que exista apenas 1 arquivo correspondente ao padrão cujo nome contenha um caractere de nova linha. Por exemplo:
fonte
Se você possui muitos arquivos e não deseja usar a
shopt -s nullglob
solução elegante e básica, pode usar find e assim por diante, desde que não imprima o nome do arquivo (que pode conter novas linhas).Ele encontrará todos os arquivos que correspondem ao log * e que não começam com
.*
- O "não nome. *" É redunante, mas é importante observar que o padrão para "ls" é não mostrar arquivos de ponto, mas o padrão pois encontrar é incluí-los.Esta é uma resposta correta e lida com qualquer tipo de nome de arquivo que você possa fornecer, porque o nome do arquivo nunca é passado entre os comandos.
Mas, a
shopt nullglob
resposta é a melhor resposta!fonte
find
vs usarls
são duas maneiras diferentes de resolver o problema.find
nem sempre está presente em uma máquina, masls
normalmente é,find
provavelmente também não tem todas essas opções sofisticadasls
.-maxdepth 1
find
faz isso por padrão. Isso pode criar confusão se você não perceber que há uma pasta filho oculta e pode tornar vantajoso o usols
em algumas circunstâncias, que não relatam arquivos ocultos por padrão.Aqui está o meu forro para isso.
fonte
set --
não está fazendo nada, exceto nos preparando$#
, que armazena o número de argumentos da linha de comando que foram passados para o programa shellVocê pode usar a opção -R para encontrar os arquivos junto com aqueles dentro dos diretórios recursivos
você pode usar padrões no grep
fonte
Um comentário importante
(reputação insuficiente para comentar)
Este é BUGGY :
Se
shopt -s nullglob
estiver definido, ele imprime o número de TODOS os arquivos regulares, não apenas aqueles com o padrão (testado no CentOS-8 e Cygwin). Quem sabe o que outros bugs sem sentidols
têm?Isso é CORRETO e muito mais rápido:
Faz o trabalho esperado.
E os tempos de execução são diferentes.
O primeiro:
0.006
no CentOS e0.083
no Cygwin (caso seja usado com cuidado).O segundo:
0.000
no CentOS e0.003
no Cygwin.fonte
Você pode definir esse comando facilmente, usando uma função shell. Este método não requer nenhum programa externo e não gera nenhum processo filho. Ele não tenta a
ls
análise perigosa e manipula caracteres “especiais” (espaços em branco, novas linhas, barras invertidas e assim por diante). Ele depende apenas do mecanismo de expansão de nome de arquivo fornecido pelo shell. É compatível com pelo menos sh, bash e zsh.A linha abaixo define uma função chamada
count
que imprime o número de argumentos com os quais foi chamada.Basta chamá-lo com o padrão desejado:
Para que o resultado seja correto quando o padrão de globbing não corresponder, a opção de shell
nullglob
(oufailglob
- que é o comportamento padrão no zsh) deve ser configurada no momento em que a expansão ocorrer. Pode ser definido assim:Dependendo do que você deseja contar, você também pode estar interessado na opção de shell
dotglob
.Infelizmente, pelo menos com o bash, não é fácil definir essas opções localmente. Se você não deseja defini-los globalmente, a solução mais direta é usar a função desta maneira mais complicada:
Se você deseja recuperar a sintaxe leve
count log*
, ou se realmente deseja evitar a geração de um subshell, pode hackear algo como:Como um bônus, esta função é de uso mais geral. Por exemplo:
Ao transformar a função em um arquivo de script (ou um programa C equivalente), que pode ser chamado pelo PATH, também pode ser composta por programas como
find
exargs
:fonte
Pensei bastante nessa resposta, especialmente considerando as coisas que não analisamos . No começo, eu tentei
que funcionava se houvesse apenas um nome de arquivo como
mas falhei se eu fizesse um nome de arquivo como este
Eu finalmente inventei o que estou colocando abaixo. Observe que eu estava tentando obter uma contagem de todos os arquivos no diretório (sem incluir nenhum subdiretório). Acho que, junto com as respostas de @Mat e @Dan_Yard, além de ter pelo menos a maioria dos requisitos estabelecidos por @mogsie (não tenho certeza sobre a memória). Acho que a resposta de @mogsie está correta, mas sempre tento me afastar da análise, a
ls
menos que seja uma situação extremamente específica.Mais facilmente:
Isso é uma descoberta específica para arquivos, delimitando a saída com um caractere nulo (para evitar problemas com espaços e alimentações de linha) e depois contando o número de caracteres nulos. O número de arquivos será um a menos que o número de caracteres nulos, pois haverá um caractere nulo no final.
Para responder à pergunta do OP, há dois casos a considerar
1) Pesquisa não recursiva:
2) Pesquisa recursiva. Observe que o conteúdo do
-name
parâmetro pode precisar ser alterado para um comportamento ligeiramente diferente (arquivos ocultos etc.).Se alguém quiser comentar sobre como essas respostas se comparam às que eu mencionei nesta resposta, faça.
Observe que cheguei a esse processo de pensamento ao obter esta resposta .
fonte
Aqui está o que eu sempre faço:
fonte
awk 'END{print NR}'
deve ser equivalente awc -l
.O que significa listar um arquivo por linha e canalizá-lo para o comando de contagem de palavras com a alternância de parâmetros para as linhas de contagem.
fonte
Para contar tudo, apenas coloque sl na linha de contagem de palavras:
Para contar com o padrão, canalize para grep primeiro:
fonte