Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to selectively traverse directory tree?

4 views
Skip to first unread message

kk_...@yahoo.com

unread,
Feb 5, 2006, 6:56:45 AM2/5/06
to
Hi. I'm looking for a shell script that will traverse a directory
tree, and when it finds a directory with a certain name, e.g.,
"UnitTest", it will do the following:

1. Check to see if there is a file called "<anything>.make", where
<anything> can be any valid file name.

2. If there is such a file, the script will execute the command "make
<filename>", where <filename> is the file found in 1. above.

I saw a posting that shows a script that traverses a tree and executes
a command. The recommendation there was to do this:

p=`pwd`
find . -type d -print | while read x; do
cd $p/$x
# exec cmd here
done
cd $p

That looks like a good start, but now I just need to know how to fill
in the missing parts.

Thanks for any help!

Ken

Stephane CHAZELAS

unread,
Feb 5, 2006, 7:19:10 AM2/5/06
to
2006-02-5, 03:56(-08), kk_...@yahoo.com:

> Hi. I'm looking for a shell script that will traverse a directory
> tree, and when it finds a directory with a certain name, e.g.,
> "UnitTest", it will do the following:
>
> 1. Check to see if there is a file called "<anything>.make", where
> <anything> can be any valid file name.
>
> 2. If there is such a file, the script will execute the command "make
> <filename>", where <filename> is the file found in 1. above.
>
> I saw a posting that shows a script that traverses a tree and executes
> a command. The recommendation there was to do this:
>
> p=`pwd`
> find . -type d -print | while read x; do
> cd $p/$x
> # exec cmd here
> done
> cd $p
[...]

Wrong start. Avoid the while read loops in shells.

find . -name the-dir-name -type d -exec sh -c '
cd -P -- "$1" || exit
for f in *.make; do
[ -f "$f" ] || continue
file=${f%.make}
[ -f "$file" ] && make "$file"
done' {} {} \;


Note that "[ -f file ]" tests whether file is a regular file or
a symbolic link to a regular file, while find's -type d checks
for files that are directories, not for files that are symbolic
links to directories. find doesn't descend into symbolic links
to directories, by default.

--
Stéphane

Chris F.A. Johnson

unread,
Feb 5, 2006, 9:15:39 AM2/5/06
to
On 2006-02-05, kk_...@yahoo.com wrote:
> Hi. I'm looking for a shell script that will traverse a directory
> tree, and when it finds a directory with a certain name, e.g.,
> "UnitTest", it will do the following:
>
> 1. Check to see if there is a file called "<anything>.make", where
><anything> can be any valid file name.
>
> 2. If there is such a file, the script will execute the command "make
><filename>", where <filename> is the file found in 1. above.

What do you want to do if there is no file *make in UnitTest? Do
you want to continue searching?

If there is, do you want to continue looking for other directories
with that name?

If there is more than one file matching *.make, do you want to
process them all? (Or is that not an issue?)

> I saw a posting that shows a script that traverses a tree and executes
> a command. The recommendation there was to do this:
>
> p=`pwd`
> find . -type d -print | while read x; do
> cd $p/$x
> # exec cmd here
> done
> cd $p
>
> That looks like a good start, but now I just need to know how to fill
> in the missing parts.

If you want to use find, you might as well have it find only the
directories you want.

Since you know the name of the directories, and there are no spaces
or other pathological characters, you can use a for loop or a while
loop:

find . -type d -name UnitTest -print |
while read dir
do
....


Or:

for dir in $(find . -type d -name UnitTest -print)
do
(
cd "$dir"
for mkf in *.make
do
if [ -f "$mkf" ]
then
make -f "$mkf"
fi
done
)
done

done


--
Chris F.A. Johnson, author | <http://cfaj.freeshell.org>
Shell Scripting Recipes: | My code in this post, if any,
A Problem-Solution Approach | is released under the
2005, Apress | GNU General Public Licence

kk_...@yahoo.com

unread,
Feb 5, 2006, 9:52:18 AM2/5/06
to
Chris F.A. Johnson wrote:

> > Hi. I'm looking for a shell script that will traverse a directory
> > tree, and when it finds a directory with a certain name, e.g.,
> > "UnitTest", it will do the following:
> >
> > 1. Check to see if there is a file called "<anything>.make", where
> ><anything> can be any valid file name.
> >
> > 2. If there is such a file, the script will execute the command "make
> ><filename>", where <filename> is the file found in 1. above.
>
> What do you want to do if there is no file *make in UnitTest? Do
> you want to continue searching?
>
> If there is, do you want to continue looking for other directories
> with that name?
>
> If there is more than one file matching *.make, do you want to
> process them all? (Or is that not an issue?)

<snip>

>
> If you want to use find, you might as well have it find only the
> directories you want.
>
> Since you know the name of the directories, and there are no spaces
> or other pathological characters, you can use a for loop or a while
> loop:
>
> find . -type d -name UnitTest -print |
> while read dir
> do
> ....
>
>
> Or:
>
> for dir in $(find . -type d -name UnitTest -print)
> do
> (
> cd "$dir"
> for mkf in *.make
> do
> if [ -f "$mkf" ]
> then
> make -f "$mkf"
> fi
> done
> )
> done
>
> done
>
>
>

There will be no more than 1 makefile in each UnitTest directory.
However there may be no makefiles there. If a UnitTest directory does
not have a make file, I do want to continue searching. It seems that
your recommendation covers this scenario. Do you agree?

Thanks!

Xicheng

unread,
Feb 5, 2006, 10:57:43 AM2/5/06
to
how about this:

find . -name "*.make" | while read -r f; do
dir=`dirname "$f"`
( cd "$dir" && make -f "$f" )
done
(untested)
use subshell ( ), you dont need to change directories frequently..Just
a suggestion.

Xicheng

Conrad J. Sabatier

unread,
Feb 6, 2006, 6:34:38 PM2/6/06
to
In article <slrndubr9u.a5f.s...@spam.is.invalid>,

Stephane CHAZELAS <this.a...@is.invalid> wrote:
>
>
>2006-02-5, 03:56(-08), kk_...@yahoo.com:
>> Hi. I'm looking for a shell script that will traverse a directory
>> tree, and when it finds a directory with a certain name, e.g.,
>> "UnitTest", it will do the following:
>>
>> 1. Check to see if there is a file called "<anything>.make", where
>> <anything> can be any valid file name.
>>
>> 2. If there is such a file, the script will execute the command "make
>> <filename>", where <filename> is the file found in 1. above.
>>
>> I saw a posting that shows a script that traverses a tree and executes
>> a command. The recommendation there was to do this:
>>
>> p=`pwd`
>> find . -type d -print | while read x; do
>> cd $p/$x
>> # exec cmd here
>> done
>> cd $p
>[...]
>
>Wrong start. Avoid the while read loops in shells.

Why?

>find . -name the-dir-name -type d -exec sh -c '
> cd -P -- "$1" || exit

How can this possibly work? Where is sh getting its arguments from?

> for f in *.make; do
> [ -f "$f" ] || continue
> file=${f%.make}
> [ -f "$file" ] && make "$file"
> done' {} {} \;
>
>
>Note that "[ -f file ]" tests whether file is a regular file or
>a symbolic link to a regular file, while find's -type d checks
>for files that are directories, not for files that are symbolic
>links to directories. find doesn't descend into symbolic links
>to directories, by default.
>
>--
>Stéphane


--
Conrad J. Sabatier <con...@cox.net> -- "In Unix veritas"

Stephane CHAZELAS

unread,
Feb 7, 2006, 3:36:54 AM2/7/06
to
2006-02-06, 23:34(+00), Conrad J. Sabatier:
[...]

>>> p=`pwd`
>>> find . -type d -print | while read x; do
>>> cd $p/$x
>>> # exec cmd here
>>> done
>>> cd $p
>>[...]
>>
>>Wrong start. Avoid the while read loops in shells.
>
> Why?

Because, by default, read doesn't to what you'd expect it does.
and because find already does a loop, so what's the point doing
the same loop (on the wrong list, as find loops on files while
while read loops on lines) in the shell as well.

>>find . -name the-dir-name -type d -exec sh -c '
>> cd -P -- "$1" || exit
>
> How can this possibly work? Where is sh getting its arguments from?
>
>> for f in *.make; do
>> [ -f "$f" ] || continue
>> file=${f%.make}
>> [ -f "$file" ] && make "$file"
>> done' {} {} \;

^^ ^^

from here.

--
Stéphane

0 new messages