Perform an action in every sub-directory using Bash

BashCommandDirectory Traversal

Bash Problem Overview


I am working on a script that needs to perform an action in every sub-directory of a specific folder.

What is the most efficient way to write that?

Bash Solutions


Solution 1 - Bash

A version that avoids creating a sub-process:

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

Or, if your action is a single command, this is more concise:

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

Or an even more concise version (thanks @enzotib). Note that in this version each value of D will have a trailing slash:

for D in */; do my_command; done

Solution 2 - Bash

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

Solution 3 - Bash

The simplest non recursive way is:

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

The / at the end tells, use directories only.

There is no need for

  • find
  • awk
  • ...

Solution 4 - Bash

Use find command.

In GNU find, you can use -execdir parameter:

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

or by using -exec parameter:

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

or with xargs command:

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

Or using for loop:

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

For recursivity try extended globbing (**/) instead (enable by: shopt -s extglob).


For more examples, see: How to go to each directory and execute a command? at SO

Solution 5 - Bash

Handy one-liners

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

find * -type d ### Option B

Option A is correct for folders with spaces in between. Also, generally faster since it doesn't print each word in a folder name as a separate entity.

# 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

Solution 6 - Bash

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

Solution 7 - Bash

This will create a subshell (which means that variable values will be lost when the while loop exits):

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

This won't:

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

Either one will work if there are spaces in directory names.

Solution 8 - Bash

the accepted answer will break on white spaces if the directory names have them, and the preferred syntax is $() for bash/ksh. Use GNU find -exec option with +; eg

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

or use a while loop

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

Solution 9 - Bash

You could try:

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

or similar...

Explanation:

find . -maxdepth 1 -mindepth 1 -type d : Only find directories with a maximum recursive depth of 1 (only the subdirectories of $1) and minimum depth of 1 (excludes current folder .)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmikewilliamsonView Question on Stackoverflow
Solution 1 - BashkanakaView Answer on Stackoverflow
Solution 2 - BashMike ClarkView Answer on Stackoverflow
Solution 3 - Bashd0xView Answer on Stackoverflow
Solution 4 - BashkenorbView Answer on Stackoverflow
Solution 5 - BashSriram MuraliView Answer on Stackoverflow
Solution 6 - BashPaul TomblinView Answer on Stackoverflow
Solution 7 - BashDennis WilliamsonView Answer on Stackoverflow
Solution 8 - Bashghostdog74View Answer on Stackoverflow
Solution 9 - BashHenry DobsonView Answer on Stackoverflow