Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perform an action in every sub-directory using Bash

People also ask

What is $_ in bash?

$_ (dollar underscore) is another special bash parameter and used to reference the absolute file name of the shell or bash script which is being executed as specified in the argument list. This bash parameter is also used to hold the name of mail file while checking emails.

What is $() in bash script?

$() Command Substitution According to the official GNU Bash Reference manual: “Command substitution allows the output of a command to replace the command itself.

What does #$ mean in bash?

#$ does "nothing", as # is starting comment and everything behind it on the same line is ignored (with the notable exception of the "shebang"). $# prints the number of arguments passed to a shell script (like $* prints all arguments). Follow this answer to receive notifications. edited Jul 9 at 13:55.


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

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

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
  • ...

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


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

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