Hoe een directorystructuur te doorkruisen op Linux

fatmawati achmad zaenuri/Shutterstock.com

Met directory’s op Linux kunt u bestanden groeperen in verschillende, afzonderlijke verzamelingen. Het nadeel is dat het vervelend wordt om van map naar map te gaan om een ​​repetitieve taak uit te voeren. Hier leest u hoe u dat kunt automatiseren.

Alles over mappen

Het eerste commando dat je leert wanneer je kennismaakt met Linux is waarschijnlijk: lsmaar cd zal er niet ver achter zitten. Het begrijpen van mappen en hoe je er omheen kunt bewegen, met name geneste submappen, is een fundamenteel onderdeel van het begrijpen hoe Linux zichzelf organiseert en hoe je je eigen werk kunt organiseren in bestanden, mappen en submappen.

Het concept van een boom met mappen begrijpen – en hoe je ertussen kunt bewegen – is een van de vele kleine mijlpalen die je passeert als je vertrouwd raakt met het landschap van Linux. Gebruik makend van cd met een pad brengt u naar die map. Snelkoppelingen zoals cd ~ of cd op zichzelf brengt u terug naar uw homedirectory, en cd .. brengt u een niveau omhoog in de directorystructuur. Gemakkelijk.

Er is echter geen even eenvoudige manier om een ​​opdracht in alle mappen van een mappenboom uit te voeren. Er zijn verschillende manieren waarop we die functionaliteit kunnen bereiken, maar er is geen standaard Linux-commando voor dat doel.

Sommige commando’s, zoals lsopdrachtregelopties hebben die hen dwingen te werken recursief, wat betekent dat ze in één map beginnen en methodisch de hele mappenboom onder die map doorlopen. Voor lshet is de -R (recursieve) optie.

Als u een opdracht moet gebruiken die recursie niet ondersteunt, moet u zelf de recursieve functionaliteit leveren. Hier is hoe dat te doen.

VERWANT: 37 Belangrijke Linux-commando’s die u moet kennen

De boom Commando

De tree Command zal ons niet helpen met de taak die voor ons ligt, maar het maakt het wel gemakkelijk om de structuur van een mappenboom te zien. Het tekent de boomstructuur in een terminalvenster zodat we direct een overzicht kunnen krijgen van de mappen en submappen die de mappenboom vormen, en hun relatieve posities in de boomstructuur.

U moet installeren tree .

Op Ubuntu moet je typen:

sudo apt install tree

Tree installeren op Ubuntu

Gebruik op Fedora:

sudo dnf install tree

Boom installeren op Fedora

Op Manjaro is het commando:

sudo pacman -Sy tree

Boom installeren op Manjaro

Gebruik makend van tree zonder parameters tekent de boom onder de huidige map.

tree

Lopende boom in de huidige map

Je kunt een pad passeren naar tree op de opdrachtregel.

tree work

Treedt op in een gespecificeerde map

De -d (mappen) optie sluit bestanden uit en toont alleen mappen.

tree -d work

Treedt op en toont alleen mappen

Dit is de handigste manier om een ​​duidelijk beeld te krijgen van de structuur van een directorystructuur. De hier getoonde directorystructuur is degene die in de volgende voorbeelden wordt gebruikt. Er zijn vijf tekstbestanden en acht mappen.

Ontleed de uitvoer van ls niet naar Traverse Directories

Je eerste gedachte zou kunnen zijn, als ls kan recursief een mappenboom doorlopen, waarom niet gebruiken ls om precies dat te doen en de uitvoer naar een aantal andere opdrachten te sturen die de regisseurs ontleden en enkele acties uitvoeren?

De uitvoer van . parseren ls wordt beschouwd als een slechte praktijk. Vanwege de mogelijkheid in Linux om bestands- en mapnamen te maken die allerlei vreemde tekens bevatten, wordt het erg moeilijk om een ​​generieke, universeel correcte parser te maken.

Je zou nooit willens en wetens een mapnaam maken die zo belachelijk is als deze, maar een fout in een script of een toepassing kan dat wel zijn.

Een bizarre directorynaam

Het parseren van legitieme maar slecht overwogen bestands- en directorynamen is foutgevoelig. Er zijn andere methoden die we kunnen gebruiken die veiliger en veel robuuster zijn dan te vertrouwen op het interpreteren van de output van ls.

Het zoekcommando gebruiken

De find Command heeft ingebouwde recursieve mogelijkheden, en het heeft ook de mogelijkheid om commando’s voor ons uit te voeren. Zo bouwen we krachtige oneliners. Als het iets is dat u in de toekomst waarschijnlijk wilt gebruiken, kunt u van uw oneliner een alias of een shell-functie maken.

Deze opdracht doorloopt recursief de directorystructuur, op zoek naar directory’s. Elke keer dat het een map vindt, drukt het de naam van de map af en herhaalt het zoeken in die map. Nadat het zoeken in één map is voltooid, verlaat het die map en hervat het zoeken in de bovenliggende map.

find work -type d -execdir echo "In:" {} ;

de opdracht find gebruiken om mappen recursief te vinden

U kunt zien aan de volgorde waarin de mappen worden weergegeven, hoe de zoekopdracht door de boom gaat. Door de uitvoer van de te vergelijken tree commando naar de uitvoer van de find oneliner, je zult zien hoe find doorzoekt elke directory en subdirectory om de beurt totdat het een directory zonder subdirectories bereikt. Het gaat dan een niveau terug en hervat het zoeken op dat niveau.

Hier is hoe de opdracht is samengesteld.

  • vind: De find opdracht.
  • werk: De directory om de zoekopdracht in te starten. Dit kan een pad zijn.
  • -type d: We zoeken regisseurs.
  • -execdir: We gaan een commando uitvoeren in elke directory die we vinden.
  • echo “In:” {}: Dit is de opdracht., We herhalen gewoon de naam van de map naar het terminalvenster. De “{}” bevat de naam van de huidige map.
  • ;: Dit is een puntkomma die wordt gebruikt om de opdracht te beëindigen. We moeten er met de backslash aan ontsnappen, zodat Bash het niet direct interpreteert.

Met een kleine verandering kunnen we ervoor zorgen dat de opdracht find bestanden retourneert die overeenkomen met een zoekaanwijzing. We moeten de -name optie en een zoek aanwijzing opnemen. In dit voorbeeld zoeken we naar tekstbestanden die overeenkomen met “*.txt”, en hun naam herhalen in het terminalvenster.

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

de opdracht find gebruiken om recursief bestanden te zoeken

Of u nu naar bestanden of mappen zoekt, hangt af van wat u wilt bereiken. Een opdracht uitvoeren: in elke mapgebruiken -type d . Een opdracht uitvoeren op elk overeenkomend bestandgebruiken -type f.

Deze opdracht telt de regels in alle tekstbestanden in de startdirectory en subdirectories.

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

Find gebruiken met het wc-commando

VERWANT: Hoe de find-opdracht in Linux te gebruiken

Directory-bomen doorkruisen met een script

Als u door mappen in een script moet gaan, kunt u de find commando in je script. Als u de recursieve zoekopdrachten zelf moet of wilt doen, kunt u dat ook doen.

#!/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"

Kopieer de tekst naar een editor en sla deze op als “recurse.sh”, gebruik vervolgens de chmod commando om het uitvoerbaar te maken.

chmod +x recurse.sh

Het recurse.sh-script uitvoerbaar maken

Het script stelt twee shell-opties in, dotglob en nullglob.

De dotglob instelling betekent bestands- en directorynamen die beginnen met een punt “.” wordt geretourneerd wanneer zoektermen met jokertekens worden uitgebreid. Dit betekent in feite dat we verborgen bestanden en mappen opnemen in onze zoekresultaten.

De nullglob instelling betekent dat zoekpatronen die geen resultaten opleveren, worden behandeld als een lege of null-tekenreeks. Ze gebruiken niet standaard de zoekterm zelf. Met andere woorden, als we naar alles in een map zoeken met behulp van het asterisk-jokerteken “*“, maar er zijn geen resultaten, we ontvangen een null-tekenreeks in plaats van een tekenreeks met een asterisk. Dit voorkomt dat het script per ongeluk een map met de naam “*” probeert te openen of “*” als een bestandsnaam behandelt.

Vervolgens definieert het een functie genaamd recursive. Dit is waar de interessante dingen gebeuren.

Er worden twee variabelen gedeclareerd, genaamd current_dir en dir_or_file . Dit zijn lokale variabelen en er kan alleen binnen de functie naar worden verwezen.

Een variabele genaamd $1 wordt ook gebruikt binnen de functie. Dit is de eerste (en enige) parameter die aan de functie wordt doorgegeven wanneer deze wordt aangeroepen.

Het script gebruikt twee for lussen, de ene genest in de andere. De eerste (buitenste) for lus wordt voor twee dingen gebruikt.

Een daarvan is om de opdracht uit te voeren die u in elke map wilt laten uitvoeren. Het enige dat we hier doen, is de naam van de map naar het terminalvenster herhalen. Je kunt natuurlijk elk commando of een reeks commando’s gebruiken, of een andere scriptfunctie aanroepen.

Het tweede dat de outer for-lus doet, is alle bestandssysteemobjecten die het kan vinden controleren, dit zijn bestanden of mappen. Dit is het doel van de innerlijke for lus. Op zijn beurt wordt elk bestand of elke mapnaam doorgegeven aan de dir_or_file variabel.

De dir_or_file variabele wordt vervolgens getest in een if-statement om te zien of het een directory is.

  • Als dat zo is, roept de functie zichzelf aan en geeft de naam van de directory door als parameter.
  • Als de dir_or_file variabele geen directory is, dan moet het een bestand zijn. Alle opdrachten die u op het bestand wilt toepassen, kunnen worden aangeroepen vanaf de else clausule van de if uitspraak. Je zou ook een andere functie binnen hetzelfde script kunnen aanroepen.

De laatste regel in het script noemt de recursive functie en passeert in de eerste opdrachtregel parameter $1 als de startdirectory om in te zoeken. Dit is het begin van het hele proces.

Laten we het script uitvoeren.

./recurse.sh work

De mappen verwerken van ondiep naar diepst

De directory’s worden doorlopen en het punt in het script waar een opdracht in elke directory zou worden uitgevoerd, wordt aangegeven door de regels “Directory-opdracht voor:”. Gevonden bestanden hebben de wc Commando’s worden erop uitgevoerd om regels, woorden en tekens te tellen.

De eerste directory die wordt verwerkt is “work”, gevolgd door elke geneste directory-tak van de boom.

Een interessant punt om op te merken is dat je de volgorde waarin de mappen worden verwerkt, kunt wijzigen door de mapspecifieke opdrachten te verplaatsen van boven de inner for-lus naar eronder.

Laten we de regel “Directory-opdracht voor:” verplaatsen naar na de done van de innerlijke for lus.

#!/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"

Nu zullen we het script nog een keer uitvoeren.

./recurse.sh work

De mappen verwerken van het diepste naar het ondiepste

Deze keer hebben de mappen eerst de commando’s op hen toegepast vanuit de diepste niveaus, terug naar de takken van de boom. De directory die als parameter aan het script is doorgegeven, wordt als laatste verwerkt.

Als het belangrijk is om eerst diepere mappen te laten verwerken, dan kunt u dat als volgt doen.

Recursie is raar

Het is alsof je jezelf belt op je eigen telefoon en een bericht voor jezelf achterlaat om jezelf te vertellen wanneer je je de volgende keer ontmoet – herhaaldelijk.

Het kan wat moeite kosten voordat je de voordelen ervan doorhebt, maar als je dat doet, zul je zien dat het een programmatisch elegante manier is om moeilijke problemen aan te pakken.

VERWANT: Wat is recursie in programmeren en hoe gebruik je het?

Leave a Comment