Globbing e Wildcards: Correspondência de Padrões de Arquivos no Linux

Globbing e Wildcards: Correspondência de Padrões de Arquivos no Linux

O que você vai conseguir fazer

  • Usar os três símbolos básicos `*`, `?` e `[]` na situação certa
  • Explicar que quem expande um glob é o shell, e não o comando
  • Evitar as armadilhas do caso sem correspondência, dos arquivos ocultos e das aspas

Pré-requisitos (leia estes primeiro)

O Que Você Vai Aprender

As palavras usadas aqui (organizadas antes)

  • Glob: uma forma de indicar vários arquivos de uma vez. Wildcard e padrão querem dizer quase a mesma coisa. Este artigo usa sempre "glob".
  • Expressão regular: uma forma de buscar dentro de um texto. O grep usa isso. É um mecanismo diferente do glob. Os símbolos se parecem, e é justamente por isso que as pessoas confundem.
  • Expansão: o shell trocando os símbolos que você escreveu por nomes de arquivo reais.
  • Arquivo oculto: um arquivo cujo nome começa com .. O exemplo clássico é o .bashrc.

No glob, o * significa "qualquer quantidade de caracteres". Na expressão regular, ele significa "repita o caractere anterior". Mesmo símbolo, sentido diferente.

Resumo Rápido

  • Qualquer caractere, qualquer quantidade -> * (ex.: *.txt)
  • Exatamente um caractere -> ? (ex.: file?.log)
  • Um caractere de um conjunto -> [] (ex.: img[0-9].png)
  • O shell expande o padrão, não o comando

1. O Que é Globbing?

Conclusão: O shell expande wildcards em nomes de arquivo antes do comando executar.

Lina: Senpai, quando eu digito ls *.txt, só os arquivos .txt aparecem. O que aquele * significa?
Veterano Linny: Boa pergunta. O * é o símbolo para "qualquer caractere, qualquer número de vezes".
Veterano Linny: E aqui está o ponto principal: quem processa o * é o shell, e não o ls.
Lina: Espera, não é o ls?
Veterano Linny: Isso mesmo. No momento em que você pressiona Enter, o shell olha para *.txt. Ele reescreve isso nos nomes de arquivo que realmente existem e entrega ao ls. Chamamos isso de expansão de glob.

Como a expansão funciona

Se o diretórioUm local que organiza arquivos. É a mesma ideia da "pasta" do Windows ou macOS. atual tem a.txt, b.txt e memo.md:

Voce digita:       ls *.txt
Shell expande:     ls a.txt b.txt      <- memo.md e excluido
ls recebe:         a.txt b.txt

ls não sabe nada sobre *. Ele apenas recebe os nomes de arquivo expandidos.

O globbing trabalha com nomes de arquivo. As expressões regulares buscam dentro de um texto, e o .* do grep é uma delas. São mecanismos diferentes. Não confunda os dois.

Primeiro, sobre evitar acidentes

O glob é poderoso junto com o rm. Ele também é perigoso. Um arquivo removido com rm não vai para a lixeira como acontece na interface gráfica. Ele some na hora.

Então crie o hábito de conferir o mesmo padrão com o ls antes de executar o rm.

$ ls *.tmp      # veja com os proprios olhos o que o padrao abrange
$ rm *.tmp      # remova so depois de ficar convencido

O terminal virtual deste site é para prática. Nada do que você digitar lá apaga um arquivo do seu computador, então experimente à vontade.

2. O Asterisco *: Qualquer String

Conclusão: O * corresponde a zero ou mais caracteres, mas nunca a um ponto inicial.

$ ls
a.txt  b.txt  data.csv  report.txt  notes.md
# Apenas arquivos terminando em .txt
$ ls *.txt
a.txt  b.txt  report.txt
Lina: Então *.txt significa "algo + .txt".
Veterano Linny: Exatamente. E lembre-se: o * também corresponde a zero caracteres. Então * sozinho significa "tudo".
Veterano Linny: E o re*?
Lina: Isso eu arrisco: "começa com re"?
Veterano Linny: Isso. O report.txt corresponde. Você pode colocar o * no início, no fim ou no meio.
# Comeca com re
$ ls re*
report.txt

# Contem data (qualquer coisa antes ou depois esta ok)
$ ls *data*
data.csv

O * não corresponde a um ponto no início, ou seja, os arquivos ocultos ficam de fora.

Executar ls * não mostra um arquivo como o .bashrc. Essa regra existe para impedir que um rm * leve junto os seus arquivos de configuração sem querer.

3. O Ponto de Interrogação ?: Qualquer Caractere Único

Conclusão: O ? corresponde a exatamente um caractere, para nomes de comprimento fixo.

$ ls
log1.txt  log10.txt  log2.txt  log3.txt
# log + um caractere + .txt (log10.txt e excluido: dois caracteres)
$ ls log?.txt
log1.txt  log2.txt  log3.txt
Lina: Então o ? é apenas um caractere. Por que o log10.txt ficou de fora?
Veterano Linny: Porque log?.txt significa "log, depois exatamente um caractere, depois .txt".
Veterano Linny: O log10.txt tem dois caracteres ali, 1 e 0. Por isso não corresponde.
Lina: E se eu quiser dois caracteres?
Veterano Linny: Escreva ??. Então log??.txt corresponde ao log10.txt.
# Dois caracteres
$ ls log??.txt
log10.txt

4. Os Colchetes []: Um Caractere de um Conjunto

Conclusão: O [] corresponde a um caractere do conjunto, com intervalos e negação.

$ ls
img0.png  img1.png  img2.png  img9.png  imgA.png

4-1. Listar os candidatos

# 0, 1 ou 2
$ ls img[012].png
img0.png  img1.png  img2.png

4-2. Usar um intervalo

# Um digito de 0-9
$ ls img[0-9].png
img0.png  img1.png  img2.png  img9.png
Lina: Então [0-9] significa "0 até 9". Posso fazer com letras também?
Veterano Linny: Pode. [a-z] para minúsculas e [A-Z] para maiúsculas. Você também pode combinar, como em [a-zA-Z0-9].
Veterano Linny: Lembre-se de que isso sempre corresponde a exatamente um caractere.

4-3. Negar (! ou ^)

# Um caractere que NAO e um digito
$ ls img[!0-9].png
imgA.png

Referência de sintaxe []

Sintaxe Significado
[abc] Um entre a / b / c
[a-z] Um caractere a-z (intervalo)
[0-9] Um caractere 0-9 (intervalo)
[!0-9] Um caractere não-dígito (negação)
[a-zA-Z] Uma letra (intervalos combinados)

5. Expansão de Chaves {}: Um Mecanismo Separado

Conclusão: A expansão de chaves constrói strings independentemente da existência dos arquivos.

# Expansao de chaves: gera tres strings
$ echo file{1,2,3}.txt
file1.txt file2.txt file3.txt
Lina: Espera, isso não é a mesma coisa que globbing?
Veterano Linny: Parece parecido, mas é completamente diferente. O {} apenas constrói textos e não verifica se os arquivos existem.
Veterano Linny: Então ele produz nomes até para arquivos que não estão lá.
Lina: Enquanto o globbing só expande para arquivos que realmente existem.
Veterano Linny: Isso mesmo. Pense no {} como "criar vários de uma vez" e no * ou [] como "escolher entre o que já existe".
# Criar diretorios numerados de uma vez (nao precisam existir)
$ mkdir log{2024,2025,2026}

# Um intervalo numerico tambem funciona
$ echo {1..5}
1 2 3 4 5

Quando * ou [] não correspondem a nenhum arquivo, o padrão fica como texto simples. Esse é o comportamento padrão do bash.

Já a expansão de chaves {} acontece sempre. Os dois se comportam de forma diferente, então tenha cuidado.

6. extglob: Globbing Estendido para Mais Poder

Conclusão: extglob habilita padrões avançados; está desabilitado por padrão.

# Habilitar globbing estendido (bash)
$ shopt -s extglob
Lina: Entendi os símbolos básicos. Posso escrever algo como "apenas .jpg e .png"?
Veterano Linny: Com o globbing padrão isso é complicado. Habilite o extglob (globbing estendido) e fica muito mais fácil.
Veterano Linny: Use @(...) para "qualquer um de" e !(...) para "exceto".

Sintaxe do extglob

Sintaxe Significado
?(pattern) Zero ou uma ocorrência
*(pattern) Zero ou mais ocorrências
+(pattern) Uma ou mais ocorrências
@(pattern) Exatamente uma (qualquer uma de)
!(pattern) Qualquer coisa exceto o padrão

Dentro de pattern, separe as alternativas com |.

# Corresponder .jpg ou .png
$ ls *.@(jpg|png)

# Tudo exceto .txt
$ ls !(*.txt)

O shopt -s extglob vale apenas para aquele shell. Feche o terminal e ele se perde.

Para desligar agora, execute shopt -u extglob.

Para ter isso sempre, adicione a linha ao seu ~/.bashrc. Isso mexe em um arquivo de configuração, então copie-o antes.

$ cp ~/.bashrc ~/.bashrc.bak
$ echo 'shopt -s extglob' >> ~/.bashrc
$ source ~/.bashrc

Se algo der errado, cp ~/.bashrc.bak ~/.bashrc restaura tudo. O >> adiciona ao final do arquivo; um > sozinho apagaria tudo, por isso não é usado aqui.

7. Armadilhas Comuns para Iniciantes

Conclusão: Comportamento sem correspondência, arquivos ocultos e aspasEnvolver um texto entre aspas (' ou ") para que seja tratado como um único valor, por exemplo um que tenha espaços. são as armadilhas clássicas.

7-1. Lina se atrapalha: sem correspondência, o padrão fica como está

# Quando nao ha arquivos .xml
$ ls *.xml
ls: cannot access '*.xml': No such file or directory
Lina: A mensagem de erro mostra *.xml sem mudar nada. O * parou de funcionar?
Veterano Linny: Ele não parou de funcionar. Ele escolheu não expandir.
Lina: Não expandir é uma opção?
Veterano Linny: É sim. Por padrão, quando nada corresponde, o bash repassa o padrão como texto simples. Por isso o ls respondeu que não existe arquivo com esse nome.
Lina: Isso muda a forma de ler o erro. É um sinal de que houve zero correspondências. Entendi.
Veterano Linny: Exatamente. E o shopt -s nullglob muda isso para não repassar nada quando houver zero correspondências.

7-2. * não captura arquivos ocultos

# Para incluir arquivos ocultos
$ shopt -s dotglob
$ ls *

Com o dotglob habilitado, o * também corresponde a arquivos ocultos. Mantê-lo desabilitado é mais seguro no dia a dia.

7-3. Aspas desabilitam globbing

# Aspas impedem * de expandir
$ ls "*.txt"
ls: cannot access '*.txt': No such file or directory

Envolver um padrão em aspas, como "*.txt" ou '*.txt', impede a expansão de glob.

Isso é útil quando você quer o * como caractere comum. Mas, se a intenção era expandir, as aspas desligam tudo sem avisar.

8. Mini Exercícios: Tente Você Mesmo

Conclusão: Três tarefas sobre extensões, comprimento e intervalos para praticar globbing.

Lina: Entendi a teoria. Quero tentar na prática.
Veterano Linny: Ótimo, preparei três exercícios. Crie os arquivos de prática primeiro, depois tente resolvê-los.

Trabalhe dentro de um diretório vazio novo. Assim nenhum dos seus arquivos existentes é tocado.

# Preparar um diretorio e arquivos de pratica
$ mkdir -p ~/glob-practice && cd ~/glob-practice
$ touch a.txt b.txt c.log data1.csv data2.csv data10.csv

Exercício 1: Liste apenas os arquivos terminados em .csv.

Ver Dica 1 (Direção)

Diga "o início do nome pode ser qualquer coisa, mas o fim precisa ser .csv". Um símbolo cobre esse início.

Ver Dica 2 (Nome do comando)

Liste com ls. O símbolo para "qualquer quantidade de caracteres" é *.

Ver Resposta
$ ls *.csv
data1.csv  data10.csv  data2.csv

Aparecem os três nomes terminados em .csv. O a.txt e o c.log ficam de fora.

Repare que o ls ordena os nomes como texto. Por isso o data10.csv vem antes do data2.csv.

Exercício 2: Liste apenas data + um caractere + .csv. Deixe o data10.csv de fora.

Ver Dica 1 (Direção)

Desta vez o comprimento é fixo. Use o símbolo de "exatamente um caractere" em vez do de "qualquer quantidade".

Ver Dica 2 (Nome do comando)

Liste com ls. O símbolo para exatamente um caractere é ?.

Ver Resposta
$ ls data?.csv
data1.csv  data2.csv

O data10.csv tem dois caracteres ali, 1 e 0, por isso ele cai fora.

Exercício 3: Mostre apenas data1.csv e data2.csv, usando colchetes.

Ver Dica 1 (Direção)

Liste você mesma os caracteres desejados. Use a forma que significa "um caractere deste conjunto".

Ver Dica 2 (Nome do comando)

Liste com ls. O conjunto vai dentro de []. Escreva 1 e 2 nele.

Ver Resposta
$ ls data[12].csv
data1.csv  data2.csv

[12] significa "um caractere, 1 ou 2". O data10.csv fica de fora.

Quando terminar, você pode remover o diretório de prática inteiro.

O -r é a opção que significa "remover o diretório e tudo o que está dentro dele". Acrescente -i e ele pergunta item por item. Olhe o conteúdo com ls antes.

$ cd ~
$ ls ~/glob-practice
$ rm -ri ~/glob-practice

9. Revisão

Lina: Vou resumir. Quem expande um glob é o shell, e não o comando.
Veterano Linny: Isso. O comando só recebe os nomes de arquivo já expandidos.
Lina: O * é qualquer quantidade de caracteres, o ? é exatamente um e o [] escolhe um do conjunto. Anotado.
Veterano Linny: É isso. E, antes de juntar um padrão com o rm, confira o mesmo padrão com o ls. Nunca pule esse passo.

Resumo do Dia em 3 Linhas

  1. Quem expande um glob é o shell, e não o comando. O comando recebe os nomes já expandidos
  2. O * corresponde a zero ou mais caracteres, o ? a exatamente um e o [] a um do conjunto
  3. Antes de juntar um padrão com o rm, confira antes com o ls

Próximas Leituras