Como percorrer uma árvore de diretórios no Linux


0
Laptop Linux mostrando um prompt bash
fatmawati achmad zaenuri/Shutterstock.com

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 lsmas cd não ficará muito atrás disso. Compreender os diretórios e como movê-los, especialmente 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 conta própria leva você de volta ao seu diretório pessoal e cd .. move você um nível acima na árvore de diretórios. Simples.

No entanto, não há 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 há um comando padrão do Linux dedicado a esse propósito.

Alguns comandos, como lstêm opções de linha de comando que os forçam a operar recursivamente, o que significa que eles começam em um diretório e trabalham metodicamente em toda a árvore de diretórios abaixo desse diretório. Por lsé o -R opção (recursiva).

Se você precisar usar um comando que não oferece suporte à recursão, precisará fornecer a funcionalidade recursiva por conta própria. Veja como fazer isso.

RELACIONADO: 37 comandos importantes do Linux que você deve conhecer

O comando da árvore

o tree O comando não nos ajudará com a 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 tree .

No Ubuntu você precisa digitar:

sudo apt install tree

Instalando a árvore no Ubuntu

No Fedora, use:

sudo dnf install tree

Instalando a árvore no Fedora

No Manjaro, o comando é:

sudo pacman -Sy tree

Instalando a árvore no Manjaro

Usando tree sem parâmetros desenha a árvore abaixo do diretório atual.

tree

Executando a árvore no diretório atual

Você pode passar um caminho para tree na linha de comando.

tree work

Executando a árvore em um diretório especificado

o -d (diretórios) exclui arquivos e mostra apenas diretórios.

tree -d work

Executando a árvore e mostrando apenas os diretórios

Essa é 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 diretórios de travessia

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

Analisando a saída de ls é considerada 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.

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

Um nome de diretório bizarro

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

Usando o comando find

o find command tem recursos recursivos embutidos e também tem 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, poderá transformar seu one-liner em um alias ou uma função de 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. Depois de concluir a pesquisa em um diretório, ele sai desse diretório e retoma a pesquisa em seu diretório pai.

find work -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 tree comando para a saída do find one-liner, você verá como find pesquisa cada diretório e subdiretório por sua 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.

  • achar: O find comando.
  • trabalhar: O diretório no qual iniciar a pesquisa. Pode ser um caminho.
  • -tipo d: Estamos procurando diretórios.
  • -execdir: Vamos executar um comando em cada diretório que encontrarmos.
  • echo “Em:” {}: Este é o comando., Estamos simplesmente ecoando o nome do diretório para a 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 os arquivos que correspondem a uma pista de pesquisa. Precisamos incluir a opção -name e uma pista de pesquisa. Neste exemplo, estamos procurando por arquivos de texto que correspondam a “*.txt” e ecoando seu nome na janela do terminal.

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

usando o comando find para encontrar arquivos recursivamente

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

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

find work -name "*.txt" -type f -execdir wc -l {} \;

Usando find com o comando wc

RELACIONADO: Como usar o comando find no Linux

Percorrendo árvores de diretórios com um script

Se você precisar percorrer diretórios dentro de um script, poderá usar o find comando dentro do seu script. Se você precisa – ou apenas quer – fazer as buscas recursivas você mesmo, você também pode fazer isso.

#!/bin/bash

shopt -s dotglob nullglob

function recursive {

  local current_dir dir_or_file

  for current_dir in $1; do

    echo "Directory command for:" $current_dir

    for dir_or_file in "$current_dir"/*; do

      if [[ -d $dir_or_file ]]; then
        recursive "$dir_or_file"
      else
        wc $dir_or_file
      fi
    done
  done
}

recursive "$1"

Copie o texto em um editor e salve-o como “recurse.sh”, então use o chmod comando para torná-lo executável.

chmod +x recurse.sh

Tornando o script recurse.sh executável

O script define duas opções de shell, dotglob e nullglob.

o dotglob configuração significa nomes de arquivos e diretórios que começam com um ponto “.” será retornado quando os termos de pesquisa curinga forem expandidos. Isso significa efetivamente que estamos incluindo arquivos e diretórios ocultos em nossos resultados de pesquisa.

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

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

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

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

O roteiro usa dois for loops, um aninhado dentro do outro. O primeiro (externo) for loop é 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ê pode usar qualquer comando ou sequência de comandos ou chamar outra função de script.

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 interior for ciclo. Por sua vez, cada nome de arquivo ou diretório é passado para o dir_or_file variável.

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

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

A linha final no script chama o recursive função e passa na primeira linha de comando parâmetro $1 como o diretório inicial para pesquisar. Isso é o que inicia todo o processo.

Vamos executar o script.

./recurse.sh work

Processando os diretórios do mais raso ao mais profundo

Os diretórios são percorridos e o ponto no script em que um comando seria executado em cada diretório é indicado pelas linhas “Directory command for:”. Os arquivos encontrados têm a wc comando executado neles 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 estar acima do loop for interno para estar abaixo dele.

Vamos mover a linha “Directory command for:” para depois do done do interior for ciclo.

#!/bin/bash

shopt -s dotglob nullglob

function recursive {

  local current_dir dir_or_file

  for current_dir in $1; do

    for dir_or_file in "$current_dir"/*; do

      if [[ -d $dir_or_file ]]; then
        recursive "$dir_or_file"
      else
        wc $dir_or_file
      fi

    done

    echo "Directory command for:" $current_dir

  done
}

recursive "$1"

Agora vamos executar o script mais uma vez.

./recurse.sh work

Processando os diretórios do mais profundo ao mais raso

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

Se for importante ter diretórios mais profundos processados ​​primeiro, é assim que você pode fazer isso.

A recursão é estranha

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

Pode levar algum esforço antes de você entender seus benefícios, mas quando você fizer isso, verá que é uma maneira programaticamente elegante de lidar com problemas difíceis.

RELACIONADO: O que é recursão na programação e como você a usa?


Like it? Share with your friends!

0

0 Comments

Your email address will not be published. Required fields are marked *