[comp.unix.wizards] Shell script help needed

jlh@loral.UUCP (Physically Pffft) (11/22/88)

Our application has it's source code in 9 directories, and I find that
often I need to make similar changes in all 9 directories.  Manually
cd'ing into each directory is error prone, some are skipped and others
are entered more than once.  I'd like to write a shell script to automate
this that would act as follows:

1.  Enter all the directory names into a file (only need to do once)
2.  Invoke the script, it reads the first directory from the file and
    cd's into it.  It then suspends itself.
3.  I do what I need to.
4.  I enter 'next' or something to wake up the script, it reads the next
    directory from the file and cd's into it.  Steps 2-4 are done for
    all directories.

My problem is I don't know how to suspend a shell script like this, and then
have it continue where it left off.  My only idea is to create a new shell
('/bin/sh'), but I think this would be slower than snail snot.  Anyone
have any ideas?  Thanks.

							Jim

-- 
Jim Harkins		jlh@loral.cts.com
Loral Instrumentation, San Diego

logan@vsedev.VSE.COM (James Logan III) (11/23/88)

In article <1872@loral.UUCP> jlh@loral.UUCP (Physically Pffft) writes:
>Our application has it's source code in 9 directories, and I find that
>often I need to make similar changes in all 9 directories.  Manually
>cd'ing into each directory is error prone, some are skipped and others
>are entered more than once.  I'd like to write a shell script to automate
>this that would act as follows:
>
>1.  Enter all the directory names into a file (only need to do once)
>2.  Invoke the script, it reads the first directory from the file and
>    cd's into it.  It then suspends itself.
>3.  I do what I need to.
>4.  I enter 'next' or something to wake up the script, it reads the next
>    directory from the file and cd's into it.  Steps 2-4 are done for
>    all directories.
>
>My problem is I don't know how to suspend a shell script like this, and then
>have it continue where it left off.  My only idea is to create a new shell
>('/bin/sh'), but I think this would be slower than snail snot.  Anyone
>have any ideas?  Thanks.

Invoking another instance of /bin/sh should not be slow since the
text segment of /bin/sh is shared by more than one process.  

I wrote you the following shell script that runs VERY quickly on
my system.  It will handle the requirements you posted.  Just type
"^D" (control-D) or "exit" to go to the next directory.

			-Jim

------------ CUT HERE --------------
#	autocd.sh	James Logan	Tue Nov 22 18:27:16 EST 1988
#		Read a list of directories from $DIRFILE and invoke
#		an interactive shell for each directory.

#
# Set DIRFILE if not already set to something else in the
# user's environment.
#
DIRFILE=${DIRFILE:-"dirs"};

if test ! -r "$DIRFILE"; then
	echo >&2 "$0: Cannot read '$DIRFILE'.";
	exit 1;
fi;

#
# Feed the file $DIRFILE into stdin and read a line at a time.
#
while read DIR; do
	echo "\nChanging to directory '$DIR'";
	if cd $DIR; then
		PS1="$DIR> ";
		export PS1;

		# Redirect stdin from user's tty -- it is currently
		# connected to $DIRFILE (inherited from the while loop).
		sh -i </dev/tty;
	fi;
done <$DIRFILE;

echo "\07\nDone.\07";
-------------- CUT HERE ------------------
-- 
Jim Logan		logan@vsedev.vse.com
(703) 892-0002		uucp:	..!uunet!vsedev!logan
			inet:	logan%vsedev.vse.com@uunet.uu.net

daniel@island.uu.net (Dan "1461 days of Bush is 1462 too many..." Smith) (11/24/88)

In article <1872@loral.UUCP> jlh@loral.UUCP (Physically Pffft) writes:
>Our application has it's source code in 9 directories, and I find that
>often I need to make similar changes in all 9 directories.  Manually
>cd'ing into each directory is error prone, some are skipped and others
>are entered more than once.  I'd like to write a shell script to automate

	I deal with this every single day! :-)

	Here's my strategy/tutorial:

	use foreach to pushd all of the directories in a tree
		[optionally set up a label]
		do whatever needs to be done the directory
		pop the directory
		[optionally goto the label]


	so from csh you could have: (skip RCS directories)

	% foreach i (`find -name RCS -prune -o -type d -print`)
	? pushd $i
	? end

	to push all all of the directories in a tree...be careful
	with $cdpath, or you may not get what you want...

	How I usually do it...

	I have an alias called "fed" (foreach directory) that sources
	a script via:

	alias	fed	'source ~$misc_bin_person/bin/ptree'

	and here is "ptree" (pushd tree)

	----
	# note, this must be sourced...
	set savecdpath=($cdpath)
	set cdpath=( . .. ../.. ../../.. ../../../../..)
	echo -n looking at directories...
	foreach i (`find -name RCS -prune -o -type d -print`)
		p $i
	end
	set cdpath=($savecdpath)
	unset savecdpath
	----

	...and here are my relevant cd/pushd/popd aliases:

	-----
#
#	aliases for setting the prompt and getting around
#
#	fillstr is a var used in prompt, contains "(level)" when dirs are pushed

set fillstr=""
set end=":-)"

alias	prompt_set 	'set prompt_head=$cwd:h;set prompt="\! $HOST"":$prompt_head:t/$cwd:t$fillstr $end "'
alias	cd	'set old=$cwd; chdir \!*; prompt_set; if -e .locrc source .locrc'
alias	dir_number	'set fillstr; set dnum=`dirs`; shift dnum; if ($#dnum >= 1) set fillstr=" ($#dnum)"'
alias	p	'set o2=$cwd; pushd \!* > /dev/null; set pdirs=`dirs`; echo $pdirs:gt; set old=$o2; dir_number; prompt_set'
alias	pp	'set o2=$cwd; popd; set old=$o2; dir_number; prompt_set'
alias	fed	'source ~$misc_bin_person/bin/ptree'
	-----

	Now...getting back to handling a tree, I go up to the root
directory of a product and type "fed".  All of the directories
get pushed, and the prompt indicates how many levels down I am.
If I'm going to do something fairly repetitive, I may set up
a label via:

% foo:

	and then do whatever I need...  then to pop directories
I enter "pp", and my prompt changes to reflect where I am and how
many directories deep...  If I had set a label, I could say something
like "goto foo" (note, no colon), and things will pretty much run
themselves until all of the directories are popped.  I take advantage
of the fact that it is an error to not have a directory to pop
to; that ends the loop.

	Hope this helps you and others that work with projects that
have many directories/levels.

				dan
-- 
DanSmith IslandGraphics 4000CivicCenterDr SanRafael MarinCo CA 94903 4154911000
415 332 FAST(h) 491 0402(Fax)|d: Nobodys' fault but mine| UnixFeastsMusicFilm
daniel@island.uu.net   unicom!daniel@pacbell.com  {lll-crg,apple}!well!dansmith

dlp@gistdev.UUCP (11/24/88)

Step 3, "I do what I need to do" is going to be a lot slower than a simple
execution of the shell, unless you're using Korn shell with an enormous
ENV file.

~/bin/dostuff:

BASEDIR=${1:-`pwd`}
for NEWDIR in `find ${BASEDIR} -type d -print`
do
	cd ${NEWDIR}
	echo	In \"${NEWDIR}\"\; Control-D to continue.
	${SHELL:=/bin/sh}
done

nick@ccicpg.UUCP (Nick Crossley) (11/24/88)

In article <1872@loral.UUCP> jlh@loral.UUCP (Physically Pffft) writes:
>... about how to do things to a set of directories ...
>
>My problem is I don't know how to suspend a shell script like this, and then
>have it continue where it left off.  My only idea is to create a new shell
>('/bin/sh'), but I think this would be slower than snail snot.  Anyone
>have any ideas?  Thanks.
>
>-- 
>Jim Harkins		jlh@loral.cts.com
>Loral Instrumentation, San Diego

I do this kind of thing sufficiently often that I wrote a script to do it,
and I did use a nested shell.  It is fast enough for my needs; your mileage
may vary.  Note that handling signals is tricky - I don't guarantee correctness!
The script is quite small, so I include it below.  It works with sh and ksh;
I don't know about csh, but I see no reason why it should not work there also.

--------------  cut here  ---------------------------------------------------
:	SCAN  -  take actions throughout a directory tree
#	Usage:  scan [-c "command"] dir ...

if	[ X$1 = X-c ]
then	Command="$2"
	shift;  shift
else	Command='echo "Now in `pwd` - type EOF to continue" ; exec ${SHELL-ksh}'
fi

exec 7<&0
{ trap '' 2 ; exec find ${*-.} -type d -print ; } |
{
trap 'continue' 2
while	read i
do
	( trap 2 ; cd $i ; eval $Command ) 0<&7
done
}

echo "Scan finished"
--------------  cut here  ---------------------------------------------------
-- 

<<< standard disclaimers >>>
Nick Crossley, CCI, 9801 Muirlands, Irvine, CA 92718-2521, USA
Tel. (714) 458-7282,  uucp: ...!uunet!ccicpg!nick

les@chinet.chi.il.us (Leslie Mikesell) (11/29/88)

In article <1872@loral.UUCP> jlh@loral.UUCP (Physically Pffft) writes:
>Our application has it's source code in 9 directories, and I find that
>often I need to make similar changes in all 9 directories. 

>My problem is I don't know how to suspend a shell script like this, and then
>have it continue where it left off.  My only idea is to create a new shell
>('/bin/sh'), but I think this would be slower than snail snot.  Anyone
>have any ideas?  Thanks.

A) Starting a new shell in each directory should not a problem, but

B) if the work just involves editing files and the directories are
   arranged such that a wild-card filename can be constructed for
   the affected files, that might be a nicer approach.  For example,
   if you are in the parent of the 9 directories you could:
   vi */xfile.c */yfile.c
   to edit all copies of xfile.c and yfile.c. A nice thing about this
   method is that you can yank and put text between files and the
   search and "." (repeat last change) commands can be used through all
   the files.

Les Mikesell