Skip to content

Execute a Command in Every Directory with Bash

July 13th, 2018 - SoftwareTutorial

TL;DR: Use a find-based loop

The other day I was wondering how to execute a command in each sub-directory of a project.

In python, you have os.walk. In C, I would’ve probably written myself something just for fun etc. In shell, I know you have find which is capable of finding all directories (find (dir) -type d). All I need to do is to wrap this in a loop and for this one has two options:

  1. Commmand line style

    find (dir) -type d | xargs ...

    or

    find (dir) -type d -exec(dir) COMMAND
  2. Script style with a loop

    while IFS= read -r d; do
    ...
    done << (find . -type d)

The choice between the two depends of the complexity of the command you want to execute inside.

Scripted approach

My use case was to execute a mvn clean in each directory ( the root dir is the container of all my maven-based development projects). Therefore, my logic would look something along the lines:

if (we have a pom in the directory)
  # execute mvn clean
else
  # do not do anything

The result is:

#!/usr/bin/env bash

ORIGINAL_PWD=`pwd`
cd "$1"

CWD=`pwd`
cleanlog="CWD/clean.log"
date > $cleanlog
SIZE_START=`du -hcs .`
while IFS= read -r d; do
    if [[ $d != *".git/"* ]]; then
      if [ -f "$d/pom.xml" ]; then
        echo "Cleaning [$d]..."
        cd "$d"
        mvn clean >> $cleanlog 2>&1
        cd "$CWD"
      fi
    fi
done < <(find . -type d)
SIZE_END=`du -hcs .`

echo "Start: ${SIZE_START}"
echo "End  : ${SIZE_END}"
cd "${ORIGINAL_PWD}"

Notes:

  • if [[ $d != *".git/"* ]]; is true if the found directory doesn’t contain the string ".git/" in it.
  • if [ -f "$d/pom.xml" ]; is true if the directory has a pom.xml file.
  • The script also shows the directory size before and after executing the loop.

HTH,

Share on
Reddit
Linked in
Whatsapp

A little experiment: