Como percorrer uma árvore de diretórios no Linux

Laptop Linux mostrando um prompt do bash

Os diretórios no Linux permitem agrupar arquivos em coleções distintas e separadas. A desvantagem é que se torna tedioso mover-se de um diretório para outro para executar uma tarefa repetitiva. Veja como automatizar isso.

Tudo sobre diretórios

O primeiro comando que você aprende quando é apresentado ao Linux é provavelmente ls, mas

 cd 

não ficará muito atrás disso. Compreender os diretórios e como movê-los, especialmente os subdiretórios aninhados, é uma parte fundamental para entender como o Linux se organiza e como você pode organizar seu próprio trabalho em arquivos, diretórios e subdiretórios.

Compreender o conceito de uma árvore de diretórios — e como se mover entre eles — é um dos muitos pequenos marcos que você passa ao se familiarizar com o cenário do Linux. Usando

 cd 

com um caminho leva você para esse diretório. Atalhos como

 cd ~ 

ou

 cd 

por si só leva você de volta ao seu diretório inicial e

 cd .. 

sobe um nível na árvore de diretórios. Simples.

No entanto, não existe um meio igualmente simples de executar um comando em todos os diretórios de uma árvore de diretórios. Existem diferentes maneiras de obter essa funcionalidade, mas não existe um comando padrão do Linux dedicado a esse propósito.

Alguns comandos, como ls, possuem opções de linha de comando que os forçam a operar recursivamente, o que significa que eles iniciam em um diretório e funcionam metodicamente em toda a árvore de diretórios abaixo desse diretório. Pois ls, é o

 -R 

opção (recursiva).

Se precisar usar um comando que não suporta recursão, você mesmo deverá fornecer a funcionalidade recursiva. Veja como fazer isso.

O comando da árvore

O treecomando não nos ajudará na tarefa em questão, mas facilita a visualização da estrutura de uma árvore de diretórios. Ele desenha a árvore em uma janela de terminal para que possamos obter uma visão geral instantânea dos diretórios e subdiretórios que compõem a árvore de diretórios e suas posições relativas na árvore.

Você precisará instalar o tree.

No Ubuntu você precisa digitar:

sudo apt instalar árvore

Instalando árvore no Ubuntu

No Fedora, use:

sudo dnf instalar árvore

Instalando árvore no Fedora

No Manjaro, o comando é:

sudo pacman -Sy árvore

Instalando árvore no Manjaro

Usar treesem parâmetros desenha a árvore abaixo do diretório atual.

árvore

Executando árvore no diretório atual

Você pode passar um caminho para treena linha de comando.

trabalho em árvore

Executando árvore em um diretório especificado

A -dopção (diretórios) exclui arquivos e mostra apenas diretórios.

árvore -d trabalho

Executando árvore e mostrando apenas diretórios

Esta é a maneira mais conveniente de obter uma visão clara da estrutura de uma árvore de diretórios. A árvore de diretórios mostrada aqui é a usada nos exemplos a seguir. Existem cinco arquivos de texto e oito diretórios.

Não analise a saída de ls para Traverse Directories

Seu primeiro pensamento pode ser: se você lspode percorrer recursivamente uma árvore de diretórios, por que não lsfazer exatamente isso e canalizar a saída para outros comandos que analisam os diretórios e executam algumas ações?

Recomendado:  Análise do Sony WH-1000XM5: os melhores fones de ouvido ANC ficaram ainda melhores

Analisar a saída de lsé considerada uma má prática. Devido à capacidade do Linux de criar nomes de arquivos e diretórios contendo todos os tipos de caracteres estranhos, torna-se muito difícil criar um analisador genérico e universalmente correto.

Talvez você nunca crie conscientemente um nome de diretório tão absurdo quanto este, mas um erro em um script ou aplicativo pode.

Um nome de diretório bizarro

A análise de nomes de arquivos e diretórios legítimos, mas mal considerados, é propensa a erros. Existem outros métodos que podemos usar que são mais seguros e muito mais robustos do que depender da interpretação da saída de ls.

Usando o comando localizar

O findcomando possui recursos recursivos integrados e também a capacidade de executar comandos para nós. Isso nos permite construir one-liners poderosos. Se for algo que você provavelmente desejará usar no futuro, você pode transformar seu one-liner em um alias ou em uma função shell.

Este comando percorre recursivamente a árvore de diretórios, procurando por diretórios. Cada vez que encontra um diretório, ele imprime o nome do diretório e repete a pesquisa dentro desse diretório. Após concluir a pesquisa em um diretório, ele sai desse diretório e retoma a pesquisa em seu diretório pai.

encontre trabalho -type d -execdir echo "In:" {} \;

usando o comando find para encontrar diretórios recursivamente

Você pode ver pela ordem em que os diretórios estão listados, como a pesquisa progride na árvore. Ao comparar a saída do treecomando com a saída do findone-liner, você verá como findpesquisa cada diretório e subdiretório por vez até atingir um diretório sem subdiretórios. Em seguida, ele volta a subir um nível e retoma a pesquisa nesse nível.

Veja como o comando é composto.

  • encontrar : o findcomando.
  • work : o diretório para iniciar a pesquisa. Pode ser um caminho.
  • -type d : Estamos procurando diretórios.
  • -execdir : Vamos executar um comando em cada diretório que encontrarmos.
  • echo “In:” {} : Este é o comando. Estamos simplesmente ecoando o nome do diretório na janela do terminal. O “{}” contém o nome do diretório atual.
  • : Este é um ponto e vírgula usado para encerrar o comando. Precisamos escapar com a barra invertida para que o Bash não a interprete diretamente.

Com uma pequena alteração, podemos fazer com que o comando find retorne arquivos que correspondam a uma pista de pesquisa. Precisamos incluir a opção -name e uma pista de pesquisa. Neste exemplo, procuramos arquivos de texto que correspondam a “*.txt” e ecoamos seus nomes na janela do terminal.

Recomendado:  Como alterar a unidade de medida da régua no Microsoft Word

find work -name "*.txt" -type f -execdir echo "Encontrado:" {} \;

usando o comando find para localizar arquivos recursivamente

A pesquisa de arquivos ou diretórios depende do que você deseja alcançar. Para executar um comando dentro de cada diretório, use -type d. Para executar um comando em cada arquivo correspondente, use -type f.

Este comando conta as linhas em todos os arquivos de texto no diretório inicial e nos subdiretórios.

encontre trabalho -name "*.txt" -type f -execdir wc -l {} \;

Usando find com o comando wc

Atravessando árvores de diretório com um script

Se você precisar percorrer diretórios dentro de um script, poderá usar o findcomando dentro do seu script. Se você precisar — ou apenas quiser — fazer as pesquisas recursivas sozinho, você também pode fazer isso.

#!/bin/bash

shopt -s dotglob nullglob

função recursiva {

local current_dir dir_or_file

para current_dir em $1; fazer

echo "Comando de diretório para:" $current_dir

para dir_or_file em "$current_dir"/*; fazer

if [[ -d $dir_or_file ]]; então

recursivo "$dir_or_file"

outro

wc $dir_or_file

fi

feito

feito

}

recursivo "$1"

Copie o texto em um editor e salve-o como “recurse.sh” e use o chmodcomando para torná-lo executável.

chmod +x recurse.sh

Tornando o script recurse.sh executável

O script define duas opções de shell dotglobe nullglob.

A dotglobconfiguração significa que nomes de arquivos e diretórios que começam com um ponto ” .” serão retornados quando os termos de pesquisa curinga forem expandidos. Isso significa efetivamente que incluímos arquivos e diretórios ocultos em nossos resultados de pesquisa.

A nullglobconfiguração significa que os padrões de pesquisa que não encontram nenhum resultado são tratados como uma sequência vazia ou nula. Eles não assumem o padrão de pesquisa em si. Em outras palavras, se estivermos procurando por tudo em um diretório usando o curinga asterisco ” *“, mas não houver resultados, receberemos uma string nula em vez de uma string contendo um asterisco. Isso evita que o script tente inadvertidamente abrir um diretório chamado “*” ou trate “*” como um nome de arquivo.

A seguir, ele define uma função chamada recursive. É aqui que as coisas interessantes acontecem.

Duas variáveis ​​são declaradas, chamadas current_dire dir_or_file. Estas são variáveis ​​locais e só podem ser referenciadas dentro da função.

Uma variável chamada $1também é usada dentro da função. Este é o primeiro (e único) parâmetro passado para a função quando ela é chamada.

O script usa dois forloops , um aninhado dentro do outro. O primeiro forloop (externo) é usado para duas coisas.

Uma é executar qualquer comando que você deseja executar em cada diretório. Tudo o que estamos fazendo aqui é ecoar o nome do diretório na janela do terminal. É claro que você poderia usar qualquer comando ou sequência de comandos ou chamar outra função de script.

Recomendado:  As maneiras mais rápidas de renomear arquivos no macOS

A segunda coisa que o loop for externo faz é verificar todos os objetos do sistema de arquivos que ele pode encontrar – que serão arquivos ou diretórios. Este é o propósito do forloop interno. Por sua vez, cada nome de arquivo ou diretório é passado para a dir_or_filevariável.

A dir_or_filevariável é então testada em uma instrução if para verificar se é um diretório.

  • Se for, a função chama a si mesma e passa o nome do diretório como parâmetro.
  • Se a dir_or_filevariável não for um diretório, deverá ser um arquivo. Quaisquer comandos que você deseja aplicar ao arquivo podem ser chamados a partir da elsecláusula da ifinstrução. Você também pode chamar outra função dentro do mesmo script.

A linha final do script chama a recursivefunção e passa o primeiro parâmetro da linha de comando $1como o diretório inicial para pesquisa. É isso que inicia todo o processo.

Vamos executar o script.

./recurse.sh funciona

Processando os diretórios do mais superficial ao mais profundo

Os diretórios são percorridos e o ponto no script onde um comando seria executado em cada diretório é indicado pelas linhas “Comando de diretório para:”. Os arquivos encontrados têm o wc comando executado para contar linhas, palavras e caracteres.

O primeiro diretório processado é “work”, seguido por cada ramificação de diretório aninhado da árvore.

Um ponto interessante a ser observado é que você pode alterar a ordem em que os diretórios são processados, movendo os comandos específicos do diretório de acima do loop for interno para abaixo dele.

Vamos mover a linha “Comando de diretório para:” para depois donedo forloop interno.

#!/bin/bash

shopt -s dotglob nullglob

função recursiva {

local current_dir dir_or_file

para current_dir em $1; fazer

para dir_or_file em "$current_dir"/*; fazer

if [[ -d $dir_or_file ]]; então

recursivo "$dir_or_file"

outro

wc $dir_or_file

fi

feito

echo "Comando de diretório para:" $current_dir

feito

}

recursivo "$1"

Agora executaremos o script mais uma vez.

./recurse.sh funciona

Processando os diretórios do mais profundo para o mais superficial

Desta vez, os diretórios têm os comandos aplicados primeiro a partir dos níveis mais profundos, trabalhando de volta aos galhos da árvore. O diretório passado como parâmetro para o script é processado por último.

Se for importante processar primeiro os diretórios mais profundos, é assim que você pode fazer isso.

A recursão é estranha

É como ligar para si mesmo em seu próprio telefone e deixar uma mensagem para si mesmo para avisar quando você se encontrar novamente – repetidamente.

Pode ser necessário algum esforço antes de você compreender seus benefícios, mas quando o fizer, verá que é uma maneira programaticamente elegante de resolver problemas difíceis.