Bash recursive scripting

How does one make a recursive script in the bash shell? For instance, if I wanted a script that stepped through the directory structure starting with . and going to the deepest level, and ran make in each folder in the tree.

Yeah, I know a makefile could be setup to do this, but it's not allowed. No, I don't understand it either. :slight_smile:

Probably because it's homework? :rolleyes:

Seriously, bash is just a programming language like others and recursion can be done two ways....

  1. starting child processes

  2. calling functions

the function calling approach is often the best because it does not keep having to spawn new processes.

However variables then become and issue, with child processes they can only inherit variables, functions can change variables.

Bash also supports local variables in functions which are not global.

Nah, it's the government sector, which sometimes feels as pointless as homework, but without the "I'll escape here one day" feeling. :slight_smile:

The system is setup so that some things have to be done in csh, some in bash, some as root, some absolutely never allowed as root, some that are best done rlogged into one machine, but that machine can never be used for actually running the sim, etc., etc. It's a monstrous conglomeration of homemade tools and outdated hardware.

It could be worse, you might have homemade hardware and outdated tools.

This is why all your variables (with carefully selected exceptions) should be local. From the iron rules of software engineering:

Thou shalt maketh your variables local and declareth them for everything else will be an abomination in the eyes of every compiler and every interpreter you might or might not run across.

bakunin

Exceptingeth a thell which doeth not thupport local, or PL/M compiler which every variable ith global unleth you declareth the prothedure reentrant, or RPG on your A-eth-400. And-lo, they altho remembered Bathic ath well.

We've got that too. :frowning:

Answering a lost question....

You don't need to use recursion, this will enumerate through directories and call a script.

find . -type d | while read N
do
     (
           cd "$N"
           if test "$?" = "0"
           then
               run-some-script.sh
           fi
     )
done

I wrote this to fix windows directories (that come inside zip files people send me)
that have spaces in directory names. Renaming files is easier.
With directories you have to go to the bottom of the tree, and then
rename going upwards, on the way out. I couldn't find a script that worked
(I found this old request instead, and several others) so I wrote this
yesterday. It seems to work just fine.

#!/bin/bash

start=$1
from=$2
to=$3

fix_from_bottom_up()
{
     for file in $1/* 
         do
         if [ -d "$file" ]; then
            fix_from_bottom_up "$file" 
                 fi
     done
     if [ -d "$1" ]; then
                base=`basename $1`
                dir=`dirname $1`
                fixedbase=`echo $base | sed "s/${from}/${to}/g"`
                if [ "$base" != "$fixedbase" ];then
                  mv $1 $dir/$fixedbase
                fi
            fi
}

if [ -z "$1" ]; then
    echo "use:  seddirnames startdir from to"
    exit;
fi

fix_from_bottom_up "$start"

Kudos, porter!! Thanks for sharing this sample code. It's very well written!

For those of you learning shell scripting, there's some good lessons in this short piece of code, so read on and I'll point out what I really like about porter's sample code:

1) Having the find command do the work, saving the trouble of writing and debugging a recursive function. Always use the tools already included in the shell and/or the UNIX/Linux command set before re-inventing the wheel!

2) Use of the read command non-interactively with the find command; very useful!

3) Use of parenthese to block all the code inside the do...done loop; this sure eliminates mucking about with semi-colons at the end of each line (and having some lines "break" because of unnecessary semi-colons).

4) Error handling: Good example of testing the exit code / return status of a command. e.g. if $test "$?" = "0" # if the exit code ($?) is True (0 zero), then the command succeeded.

------------
NOTES: The use of the double quotes around the variable $N makes the test code above necessary, should the directory (file) name contain one or more blank spaces. With the variable N in single quotes, the cd command would work regardless of blank spaces in the file name. Read about Quoting to find out more.

If a directory name contained non-printable charactes (symbols, device codes, etc.), and the read command never passed them into the variable N, then the cd command would fail.

Directory permissions might cause cd to fail; another reason to handle expected and unexpected errors!

Kudos, porter!

The code below (as written anyway) won't always work,
I don't believe. Not if the purpose of run-some-script.sh
is to rename directories on the fly. Find (it must, I think)
make a list of names to iterate over. So, if you change a directory
name, then all the subdirectories below that one suddenly have
invalid names, and the script will blow up. There might be a way
to use find -depth......but at least as written, I don't think the code
below would work for directory renaming.....

find . -type d | while read N
do
(
cd "$N"
if test "$?" = "0"
then
run-some-script.sh
fi
)
done

---------------------

You raise a good question.

Have you had a chance to test it?

.