Backwards "search" in directories

Backwards "search" in directories

am 07.11.2007 12:24:13 von Kenneth Brun Nielsen

I would like an easy way to setup a (environment) variable based on
the location in the directory structure.

My idea is to place an empty file (eg. ".projectroot") at the top of
the respective project. When some script ProjectRoot is called from a
subdirectory of this directory it goes backwards in the hierarchy
until it finds the .projectroot file. The location of the .projectroot
file is printed to (env) variable $PROJECTROOT.

I'm pretty ignorant, when it comes to Unix shell scripting. Can you
help me on this. Example:

touch /home/kbn/project1/.projectroot
cd /home/kbn/project1/subdir1/subdir2/
$PROJECTROOT = `ProjectRoot`

How can I implement the script ProjectRoot?

Best regards,
Kenneth

Re: Backwards "search" in directories

am 07.11.2007 13:19:24 von parv

in message <1194434653.816167.71220@o80g2000hse.googlegroups.com>,
wrote Kenneth Brun Nielsen ...

> My idea is to place an empty file (eg. ".projectroot") at the top
> of the respective project. When some script ProjectRoot is called
> from a subdirectory of this directory it goes backwards in the
> hierarchy until it finds the .projectroot file. The location of
> the .projectroot file is printed to (env) variable $PROJECTROOT.
>
> I'm pretty ignorant, when it comes to Unix shell scripting. Can
> you help me on this. Example:
>
> touch /home/kbn/project1/.projectroot
> cd /home/kbn/project1/subdir1/subdir2/
> $PROJECTROOT = `ProjectRoot`

That assignment won't work; it should be ...

PROJECTROOT=`ProjectRoot`


> How can I implement the script ProjectRoot?

Basically ...

1 look in the current directory for the file;
2 if found, stop;
3 else change to parent directory until it is /;
4 repeat 1-3.


... here is my first attempt, not fully tested, based on ash as found
in FreeBSD 6[0] (save it in a file and give it execute permissions)
....

#!/bin/sh

# (Try to) Get a full path of the script to call itself
# recursively from different directories.
self="$0"
case "$self" in
/* )
;;

* )
self="${PWD}/$0"
;;
esac

find_file()
{
local search
search="${1}"
shift

local found
found=

stat "./${search}" >/dev/null 2>&1 && found=1

case "${PWD}" in
/ )
;;

# Recurse.
* )
[ -z "${found}" ] \
&& ( cd .. && "${self}" "${search}" )
;;
esac

[ -n "${found}" ] \
&& printf "found '%s' in '%s'\n" "${search}" "${PWD}"
}

for i in ${@}
do
find_file "${i}"
done


[0] Comments about improving portability among bourne-like shells
is quite welcome.


- parv

--
Undo WhereElse from address for private mail.

Re: Backwards "search" in directories

am 07.11.2007 13:32:42 von parv

in message ,
wrote parv ...

> .. here is my first attempt, not fully tested, based on ash as found
> in FreeBSD 6[0] (save it in a file and give it execute permissions)
....
> # Recurse.
> * )
> [ -z "${found}" ] \
> && ( cd .. && "${self}" "${search}" )
^ ^
^ ^
> ;;
....

Sub-shell context above is superflous; the 'cd' command should just
be ...

[ -z "${found}" ] \
&& cd .. && "${self}" "${search}"


- parv

--

Re: Backwards "search" in directories

am 07.11.2007 13:44:24 von parv

in message ,
wrote parv ...

> in message ,
> wrote parv ...
>
>> .. here is my first attempt, not fully tested, based on ash as found
>> in FreeBSD 6[0] (save it in a file and give it execute permissions)
> ...
>> # Recurse.
>> * )
>> [ -z "${found}" ] \
>> && ( cd .. && "${self}" "${search}" )
> ^ ^
> ^ ^
>> ;;
> ...
>
> Sub-shell context above is superfluous; the 'cd' command should just
> be ...
>
> [ -z "${found}" ] \
> && cd .. && "${self}" "${search}"

Oh never mind. Sub-shell is quite useful in the original script
which iterated over all the given arguments.

Otherwise, the script instance executed by the user would find
itself outside of the directory where it was executed. (So if given
two file names, in order, one in somewhere in directories above and
one in the current directory, the file in the current will not be
found as the script instance itself went up the chain.)


- parv

--

Re: Backwards "search" in directories

am 07.11.2007 14:03:29 von Kenneth Brun Nielsen

It prints out the execution location each time though the file name
does not exist there, e.g.
found 'whateverfilename' in '/path/of/execution/'

I would love to debug it myself, but I simply don't understand some of
the syntax

On Nov 7, 1:19 pm, parv wrote:

> #!/bin/sh
>
> self="$0"
> case "$self" in
> /* )
> ;;
>
> * )

I don't understand these parantheses incl. /* and ;;

> self="${PWD}/$0"
> ;;
> esac

> find_file()
> {
> local search
> search="${1}"
> shift
>
> local found
> found=
>
> stat "./${search}" >/dev/null 2>&1 && found=1

I understand close to nothing of this line.

> case "${PWD}" in
> / )
> ;;
>
> # Recurse.
> * )
> [ -z "${found}" ] \
> && ( cd .. && "${self}" "${search}" )
> ;;
> esac
>
> [ -n "${found}" ] \
> && printf "found '%s' in '%s'\n" "${search}" "${PWD}"
> }
>
> for i in ${@}

I know this is not the most critical place, but I assume ${@} reflect
all command line parameters or something similar?

> do
> find_file "${i}"
> done

Thanks for your effort - I hope you can help me to the end:-)

Best regards,
Kenneth

Re: Backwards "search" in directories

am 07.11.2007 14:36:40 von Kenneth Brun Nielsen

On Nov 7, 1:19 pm, parv wrote:

> stat "./${search}" >/dev/null 2>&1 && found=1

I debugged a little further, and this above line seems to be the
problem. I think it always produces a "1"...

/Kenneth

Re: Backwards "search" in directories

am 07.11.2007 16:17:46 von cfajohnson

On 2007-11-07, Kenneth Brun Nielsen wrote:
>
>
> I would like an easy way to setup a (environment) variable based on
> the location in the directory structure.
>
> My idea is to place an empty file (eg. ".projectroot") at the top of
> the respective project. When some script ProjectRoot is called from a
> subdirectory of this directory it goes backwards in the hierarchy
> until it finds the .projectroot file. The location of the .projectroot
> file is printed to (env) variable $PROJECTROOT.
>
> I'm pretty ignorant, when it comes to Unix shell scripting. Can you
> help me on this. Example:
>
> touch /home/kbn/project1/.projectroot
> cd /home/kbn/project1/subdir1/subdir2/
> $PROJECTROOT = `ProjectRoot`
>
> How can I implement the script ProjectRoot?

proot=.projectroot
while [ ! -f "$proot" ]
do
cd ..
case $PWD in /) break ;; esac
done

--
Chris F.A. Johnson, author
Shell Scripting Recipes: A Problem-Solution Approach (2005, Apress)
===== My code in this post, if any, assumes the POSIX locale
===== and is released under the GNU General Public Licence

Re: Backwards "search" in directories

am 07.11.2007 16:30:51 von Kenneth Brun Nielsen

On Nov 7, 4:17 pm, "Chris F.A. Johnson" wrote:
> On 2007-11-07, Kenneth Brun Nielsen wrote:
>
>
>
>
>
>
>
> > I would like an easy way to setup a (environment) variable based on
> > the location in the directory structure.
>
> > My idea is to place an empty file (eg. ".projectroot") at the top of
> > the respective project. When some script ProjectRoot is called from a
> > subdirectory of this directory it goes backwards in the hierarchy
> > until it finds the .projectroot file. The location of the .projectroot
> > file is printed to (env) variable $PROJECTROOT.
>
> > I'm pretty ignorant, when it comes to Unix shell scripting. Can you
> > help me on this. Example:
>
> > touch /home/kbn/project1/.projectroot
> > cd /home/kbn/project1/subdir1/subdir2/
> > $PROJECTROOT = `ProjectRoot`
>
> > How can I implement the script ProjectRoot?
>
> proot=.projectroot
> while [ ! -f "$proot" ]
> do
> cd ..
> case $PWD in /) break ;; esac
> done

Thanks, Chris. I took a quick google-refered crash course in Unix
shell programming. This is what I ended up with (quite similar in
structure to yours):

#!/bin/sh

searchpath="${PWD}"
searchfile=".projectroot"

while [ ! -f "${searchpath}/${searchfile}" -a "$searchpath" != "/" ]
do
cd "${searchpath}/..";searchpath="${PWD}"
done

[ ! -f "${searchpath}/${searchfile}" ] && exit 1
[ -f "${searchpath}/${searchfile}" ] && echo "${searchpath}"

Let me know, if something looks too crazy...

/Kenneth

Re: Backwards "search" in directories

am 07.11.2007 16:50:35 von Icarus Sparry

On Wed, 07 Nov 2007 10:17:46 -0500, Chris F.A. Johnson wrote:

> On 2007-11-07, Kenneth Brun Nielsen wrote:
>>
>>
>> I would like an easy way to setup a (environment) variable based on the
>> location in the directory structure.
>>
>> My idea is to place an empty file (eg. ".projectroot") at the top of
>> the respective project. When some script ProjectRoot is called from a
>> subdirectory of this directory it goes backwards in the hierarchy until
>> it finds the .projectroot file. The location of the .projectroot file
>> is printed to (env) variable $PROJECTROOT.
>>
>> I'm pretty ignorant, when it comes to Unix shell scripting. Can you
>> help me on this. Example:
>>
>> touch /home/kbn/project1/.projectroot
>> cd /home/kbn/project1/subdir1/subdir2/
>> $PROJECTROOT = `ProjectRoot`
>>
>> How can I implement the script ProjectRoot?
>
> proot=.projectroot
> while [ ! -f "$proot" ]
> do
> cd ..
> case $PWD in /) break ;; esac
> done

Good start, but fails to produce any output.

One thing that is not clear is if the original poster wanted a relative
path in the output, i.e. to have PROJECTROOT set to ../.. or maybe ../../
in the example, or if they wanted an absolute path, i.e. to have
PROJECTROOT set to /home/kbn/project1.

The syntax to set a variable in shell is
PROJECTROOT=`ProjectRoot`
or
PROJECTROOT=$(ProjectRoot)
note there are no spaces around the equals sign, and no dollar on the
variable name.

Here is a ProjectRoot script.

#!/bin/bash
output=
while [ ! -f ".projectroot" ]
do
cd ..
case $PWD in (/) echo "No .projectroot found" >&2; exit 1;; esac
output="../$output"
done
# choose one of the next lines, depending on the output required
printf "%s" "$PWD"
echo $output
echo ${output%/}
echo ${output:-./}
output=${output:-./};echo ${output%/}