Voer een actie uit in elke submap met Bash

Ik werk aan een script dat een actie moet uitvoeren in elke submap van een specifieke map.

Wat is de meest efficiënte manier om dat te schrijven?


Antwoord 1, autoriteit 100%

Een versie die het maken van een subproces vermijdt:

for D in *; do
    if [ -d "${D}" ]; then
        echo "${D}"   # your processing here
    fi
done

Of, als uw actie een enkele opdracht is, is dit beknopter:

for D in *; do [ -d "${D}" ] && my_command; done

Of een nog beknoptere versie (bedankt @enzotib). Merk op dat in deze versie elke waarde van Deen afsluitende slash heeft:

for D in */; do my_command; done

Antwoord 2, autoriteit 59%

for D in `find . -type d`
do
    //Do whatever you need with D
done

Antwoord 3, autoriteit 40%

De eenvoudigste niet recursievemanier is:

for d in */; do
    echo "$d"
done

De /aan het einde vertelt, gebruik alleen mappen.

Het is niet nodig

  • vinden
  • awk

Antwoord 4, autoriteit 7%

Gebruik de opdracht find.

In GNU findkunt u de parameter -execdirgebruiken:

find . -type d -execdir realpath "{}" ';'

of door de parameter -execte gebruiken:

find . -type d -exec sh -c 'cd -P "$0" && pwd -P' {} \;

of met xargscommando:

find . -type d -print0 | xargs -0 -L1 sh -c 'cd "$0" && pwd && echo Do stuff'

Of gebruik forlus:

for d in */; { echo "$d"; }

Voor recursiviteit, probeer in plaats daarvan uitgebreide globbing (**/) (inschakelen door: shopt -s extglob).


Voor meer voorbeelden, zie: Hoe ga je naar elke map en voer je een commando uit?bij SO


Antwoord 5, autoriteit 4%

Handige oneliners

for D in *; do echo "$D"; done
for D in *; do find "$D" -type d; done ### Option A
find * -type d ### Option B

Optie A is juist voor mappen met spaties ertussen. Over het algemeen ook sneller omdat het niet elk woord in een mapnaam als een afzonderlijke entiteit afdrukt.

# Option A
$ time for D in ./big_dir/*; do find "$D" -type d > /dev/null; done
real    0m0.327s
user    0m0.084s
sys     0m0.236s
# Option B
$ time for D in `find ./big_dir/* -type d`; do echo "$D" > /dev/null; done
real    0m0.787s
user    0m0.484s
sys     0m0.308s

Antwoord 6, autoriteit 3%

find . -type d -print0 | xargs -0 -n 1 my_command


Antwoord 7, autoriteit 2%

Hierdoor wordt een subshell gemaakt (wat betekent dat variabelewaarden verloren gaan wanneer de while-lus wordt afgesloten):

find . -type d | while read -r dir
do
    something
done

Dit zal niet:

while read -r dir
do
    something
done < <(find . -type d)

Beide werken als er spaties zijn in directorynamen.


Antwoord 8, autoriteit 2%

Je zou kunnen proberen:

#!/bin/bash
### $1 == the first args to this script
### usage: script.sh /path/to/dir/
for f in `find . -maxdepth 1 -mindepth 1 -type d`; do
  cd "$f"
  <your job here>
done

of vergelijkbaar…

Uitleg:

find . -maxdepth 1 -mindepth 1 -type d:
Vind alleen mappen met een maximale recursieve diepte van 1 (alleen de submappen van $1) en een minimale diepte van 1 (exclusief huidige map .)


Antwoord 9, autoriteit 2%

het geaccepteerde antwoord wordt onderbroken door spaties als de directorynamen die hebben, en de voorkeurssyntaxis is $()voor bash/ksh. Gebruik GNU find-execoptie met +;bijv.

find .... -exec mycommand +;#this is same as passing to xargs

of gebruik een while-lus

find .... | while read -r D
do
    # use variable `D` or whatever variable name you defined instead here
done 

Other episodes