Como Ordenar Nomes de Arquivos no Bash Mantendo os Caminhos

Por Mizael Xavier
Como Ordenar Nomes de Arquivos no Bash Mantendo os Caminhos

Ordenando Arquivos por Nome Preservando Caminhos no Bash

Trabalhar com arquivos no terminal Bash é uma tarefa fundamental para muitos desenvolvedores e administradores de sistemas. Uma necessidade comum é listar arquivos e ordená-los de uma maneira específica. No entanto, quando precisamos listar arquivos com seus caminhos completos e ordená-los pelo nome do arquivo (e não pelo caminho inteiro), a tarefa pode parecer complexa à primeira vista. Métodos simples como ls | sort geralmente não produzem o resultado desejado nesse cenário, além de serem desaconselhados para parseamento em scripts.

O Desafio da Ordenação com Caminhos Completos

Imagine que você tem uma estrutura de diretórios e deseja listar todos os arquivos .txt, ordenados alfabeticamente pelos seus nomes, mas exibindo o caminho completo de cada um. Se você usar find . -name '*.txt' | sort, a ordenação será feita com base na string inteira do caminho (ex: ./a/b/arquivo1.txt, ./z/arquivo0.txt). Isso significa que ./a/b/arquivo1.txt viria antes de ./z/arquivo0.txt, mesmo que 'arquivo0' devesse vir antes de 'arquivo1' na ordenação desejada pelo nome do arquivo.

Utilizando find e sort para Ordenação Básica

O comando find é a ferramenta padrão e mais robusta para localizar arquivos no sistemas Unix-like. Ele oferece grande flexibilidade para buscar arquivos com base em diversos critérios (nome, tipo, data, etc.). Combinado com o comando sort, podemos ordenar a lista de arquivos encontrada. Como vimos, a ordenação padrão do sort aplicada diretamente à saída do find (que por padrão lista caminhos) ordena pelo caminho completo.

find . -type f # Lista todos os arquivos com seus caminhos relativos

find . -type f | sort # Ordena a lista acima lexicalmente pelo caminho completo

A Solução: Isolando o Nome do Arquivo para Ordenação

Para ordenar efetivamente pelos nomes dos arquivos, mas ainda assim exibir os caminhos completos, precisamos de uma estratégia que permita ao sort focar apenas na porção do nome do arquivo. A abordagem mais eficiente e elegante utiliza as opções de formatação do próprio comando find.

Método com find -printf

O comando find possui a ação -printf, que permite formatar a saída de maneira personalizada. Podemos usá-la para imprimir primeiro o nome do arquivo (sem o caminho) e depois o caminho completo, separados por um caractere que não exista nos nomes dos arquivos, como uma tabulação (\t).

find . -type f -printf '%f\t%p\n'

Neste comando:

  • %f: Imprime apenas o nome do arquivo (basename).
  • \t: Imprime um caractere de tabulação literal.
  • %p: Imprime o caminho completo do arquivo encontrado.
  • \n: Imprime uma nova linha.

A saída será algo como:

arquivoZ.txt	./dir1/arquivoZ.txt
arquivoA.txt	./dir2/arquivoA.txt

Agora, podemos passar essa saída para o sort. Como a tabulação separa o nome do arquivo (a chave de ordenação desejada) do resto da linha, o sort padrão ordenará corretamente com base no nome do arquivo:

find . -type f -printf '%f\t%p\n' | sort

A saída ordenada será:

arquivoA.txt	./dir2/arquivoA.txt
arquivoZ.txt	./dir1/arquivoZ.txt

Finalmente, para obter apenas os caminhos completos ordenados, usamos o comando cut para remover a primeira coluna (o nome do arquivo usado para ordenação) e o caractere de tabulação:

find . -type f -printf '%f\t%p\n' | sort | cut -f2-

O cut -f2- instrui o comando a extrair do segundo campo (-f2) até o final da linha (-), usando a tabulação como delimitador padrão. O resultado final será a lista de caminhos completos, ordenada pelos nomes dos arquivos.

Variações com Opções do `sort`

A beleza dessa abordagem é que podemos facilmente aplicar diferentes opções do sort para lidar com casos específicos, como nomes de arquivos numéricos ou versões. Por exemplo, para ordenação numérica:

find . -type f -printf '%f\t%p\n' | sort -n | cut -f2-

Para ordenação de versões (útil para arquivos como script-1.0.sh, script-2.0.sh, script-10.0.sh):

find . -type f -printf '%f\t%p\n' | sort -V | cut -f2-

Alternativa com `basename` (Menos Eficiente)

Embora funcional, usar um loop `while read` combinado com o comando `basename` para extrair o nome do arquivo dentro do loop é geralmente menos performático do que a solução com find -printf, especialmente para um grande número de arquivos, pois envolve a execução de um processo externo (`basename`) para cada arquivo encontrado.

find . -type f | while read -r file; do printf '%s\t%s\n' "$(basename "$file")" "$file"; done | sort | cut -f2-

Esta alternativa é mais verbosa e menos eficiente, tornando a abordagem -printf a escolha preferida.


Em resumo, a combinação de find -printf '%f\t%p\n', sort (com suas diversas opções como -n ou -V) e cut -f2- oferece uma solução robusta, eficiente e flexível para o desafio de ordenar arquivos pelos seus nomes enquanto se preserva e exibe seus caminhos completos no Bash. Dominar essa técnica aprimora significativamente a capacidade de manipulação de arquivos no terminal.

Mizael Xavier

Mizael Xavier

Desenvolvedor e escritor técnico

Ver todos os posts

Compartilhar: