[net.unix] Exporting shell functions into shell files

rob@alice.UucP (Rob Pike) (11/20/85)

I will use two examples to explain why you want to export shell functions:
	hide() {
		for i in $*
		do
			eval $i'(){ echo "hidden '$i' $*" }' 
			export $i
		done
	}
hide takes a list of names and makes empty functions from them: functions
that just echo that they were called, but that do nothing.  (Note the pretty
indirection: this function makes more functions.)  This is useful
for debugging shell scripts and makefiles:
	% hide rm
	% rm foo
	hidden rm foo
	%
rm didn't really run, but you can see it would have.  So if "futz" is a shell
program you're working on that (once working) removes things, you can
debug futz without fear of losing precious files.  It's more useful that
these be functions than files because there is nothing to clean up later:
the functions go away when the shell you're working in disappears - when you
log off or delete the window.

A simpler example is that you can define a cc() function that sets an
extra argument so a makefile doesn't need to be examined or modified to
set CFLAGS.  Setting CFLAGS itself would work, but only if it is used
religiously in the makefile and if you know what value it has inside
(you can't add to it, only redefine it):
	% cc() /bin/cc -p $*
	% make a.out
will make a profiled version of a.out (assuming cc is called to compile it)
regardless of how the makefile is written.

The point about functions not being understood in csh files is valid, but
not interesting to me - my shell files are all sh files.


					Rob Pike

levy@ttrdc.UUCP (Daniel R. Levy) (11/21/85)

In article <4588@alice.UUCP>, rob@alice.UucP (Rob Pike) writes:
>I will use two examples to explain why you want to export shell functions:
>	hide() {
>		for i in $*
>		do
>			eval $i'(){ echo "hidden '$i' $*" }'
>			export $i
>		done
>	}
>hide takes a list of names and makes empty functions from them: functions
>that just echo that they were called, but that do nothing.  (Note the pretty
>indirection: this function makes more functions.)  This is useful
>for debugging shell scripts and makefiles:
>	% hide rm
>	% rm foo
>	hidden rm foo
>	%
>rm didn't really run, but you can see it would have.  So if "futz" is a shell
>program you're working on that (once working) removes things, you can
>debug futz without fear of losing precious files.  It's more useful that
>these be functions than files because there is nothing to clean up later:
>the functions go away when the shell you're working in disappears - when you
>log off or delete the window.
>A simpler example is that you can define a cc() function that sets an
>extra argument so a makefile doesn't need to be examined or modified to
>set CFLAGS.  Setting CFLAGS itself would work, but only if it is used
>religiously in the makefile and if you know what value it has inside
>(you can't add to it, only redefine it):
>	% cc() /bin/cc -p $*
>	% make a.out
>will make a profiled version of a.out (assuming cc is called to compile it)
>regardless of how the makefile is written.
>The point about functions not being understood in csh files is valid, but
>not interesting to me - my shell files are all sh files.
>
>					Rob Pike

This makes the purpose a bit clearer to me (I presume this is in response
to my query of why export functions) but there is still another way to
get around this (wanting to alter the function of ordinary unix commands
in sh scripts, makefiles, etc).  Just create a one or two-line shell script
in a directory searched early in your $PATH like $HOME/bin, or even some-
thing like $HOME/hackbin :-).  Then that script gets
referenced, instead of the usual command.  By this token, you could do:

	hackpath() {
		if test -z "`echo $PATH | grep $HOME/hackbin`"
		then
			if test ! -d $HOME/hackbin
			then
				/bin/mkdir $HOME/hackbin
			fi
			PATH=$HOME/hackbin:$PATH
			export PATH
		fi
	}

	hide() {
		hackpath
		for i in $*
		do
			/bin/echo /bin/echo hidden $i > $HOME/hackbin/$i
			/bin/chmod u+x $HOME/hackbin/$i
		done
	}

and

	unhide() {
		for i in $*
		do
			/bin/rm -f $HOME/hackbin/$i
		done
	}

and

	customize() {
		hackpath
		for i in $*
		do
			/bin/echo Enter custom command for $i:
			read answer
			/bin/echo "$answer" > $HOME/hackbin/$i
			/bin/chmod u+x $HOME/hackbin/$i
		done
	}

The sh's the limit here :-), and you didn't have to export a single function.

friesen@psivax.UUCP (Stanley Friesen) (11/26/85)

>In article <4588@alice.UUCP>, rob@alice.UucP (Rob Pike) writes:
>>I will use two examples to explain why you want to export shell functions:
>
>>hide takes a list of names and makes empty functions from them: functions
>>that just echo that they were called, but that do nothing.  
>>  This is useful
>>for debugging shell scripts and makefiles:
>>	% hide rm
>>	% rm foo
>>	hidden rm foo
>>	%
>>rm didn't really run, but you can see it would have.  So if "futz" is a shell
>>program you're working on that (once working) removes things, you can
>>debug futz without fear of losing precious files.  It's more useful that
>>these be functions than files because there is nothing to clean up later:
>>the functions go away when the shell you're working in disappears - when you
>>log off or delete the window.

	The problem with this is that it creates a serious security
hole. A user may inadvertantly or maliciously redefine a command used
by a system shell script changing its behavior radically. A system
command that suddenly stops using due to some independent action or
which can be made to do whatever the user wants by tricking it into
executing the user's program is very dangerous.
	Thus this sort of facility *must* have an escape mechanism.
There shold be a simple, direct way of *deleting* *all* defined shell
functions in a secure shell script. You know something like 'undefine all'.
Without this the mechanism is too dangerous.
-- 

				Sarima (Stanley Friesen)

UUCP: {ttidca|ihnp4|sdcrdcf|quad1|nrcvax|bellcore|logico}!psivax!friesen
ARPA: ttidca!psivax!friesen@rand-unix.arpa

seifert@hammer.UUCP (Snoopy) (11/30/85)

In article <878@psivax.UUCP> friesen@psivax.UUCP (Stanley Friesen) writes:

>	The problem with this is that it creates a serious security
>hole. A user may inadvertantly or maliciously redefine a command used
>by a system shell script changing its behavior radically. A system
>command that suddenly stops using due to some independent action or
>which can be made to do whatever the user wants by tricking it into
>executing the user's program is very dangerous.

How is this different from having your own bin directory, which
is the first bin in your PATH?  You can redefine commands that way
too.  This security hole is easy to plug.  System commands that
call other system commands should use the full pathname, e.g.
/bin/rm, rather than just rm.  Of course this means that commands
called by other commands have to stay in a known place, and can't
just float all over the universe.

Snoopy (ECS Ronin #901)
tektronix!tekecs!doghouse.TEK!snoopy